2014-10-16

Python: how to start independent process

Задача: запустить полностью независимый процесс из Python. Попробуем стартовать в Linux простой HTTP сервер и отправить его в свободное плавание:

import subprocess
subprocess.Popen(['python', '-m', 'SimpleHTTPServer', '5000'], close_fds=True)
Однако параметр "close_fds" в Windows не работает: "Note that on Windows, you cannot set close_fds to true". Как вариант, можно использовать стандартные компоненты Windows, cmd.exe и команду start:

import subprocess
subprocess.Popen([‘C:\Windows\System32\cmd.exe’, ‘/C’, ’start’, ‘C:\Python27\Python.exe’, ‘-m’, ’SimpleHTTPServer’, ‘5000’])
Это создаст новое окно cmd.exe, где будет запущен http-сервер. Что и требовалось.

2014-09-16

Работа с Azure SQL из PHP в Ubuntu

Приведу пример, как это делается в Ubuntu. Установим нужные пакеты

sudo apt-get install php5-cli php5-sybase freetds*

Изменим файл концигурации FreeTDS /etc/freetds/freetds.conf, добавив секцию

[xxxserver.database.windows.net]
    host = xxxserver.database.windows.net
    port = 1433
    tds version = 8.0

Короткий кусочек кода на PHP5

<?php
$server = 'xxxserver';
$dbname = 'xxxdbname';
$user = "xxxuser@{$server}";
$passwd = 'xxxpassword';

$p = new PDO("dblib:host={$server}.database.windows.net;dbname={$dbname}", $user, $passwd);
foreach($p->query('SELECT col FROM table') as $row){
        echo $row['term'];
}
?>

Это очень актуально для Yii-фреймворка.

2014-08-13

Python: how to stop process correctly

Одной из задач, с которой встречаются разработчики многопоточных/многопроцессных приложений, является их корректная остановка. Особенно это касается таких потоков/процессов, в которых осуществляется бесконечная блокирующая операция, типа цикла "while True" или чтения из некоего генератора.

while True:
    # do something
С потоками проще, потому что им можно передать ссылку на объект, который можно проверять при каждой итерации и останавливать при соблюдении условий.

import time
from threading import Thread

def in_thread(con):
    while con[0]:
        # ... doing something
        pass

con = [True]
t = Thread(target=in_thread, args=(con,))
t.start()

time.sleep(3)
# Stop the thread
con[0] = False
t.join()
С процессами несколько иначе, они более изолированные, и нужно использовать объекты синхронизации. Очень удобный способ мне подсказал коллега, с использованием Lock.

import time
from threading import Thread
from multiprocessing import Process, Lock

def in_process(lock):

    def in_thread(con):
        while con[0]:
            pass
            # ... doing something

    con = [True]
    t = Thread(target=in_thread, args=(con,))
    t.daemon = True
    t.start()

    # Lock acquired in parent process, child process waits, but thread already ran!
    lock.acquire()

    # Polite way
    con[0] = False
    t.join()

    # Way for impatient
    # import os
    # os._exit(0)


lock = Lock()
lock.acquire()
Process(target=in_process, args=(lock,)).start()

time.sleep(3)
# ... process in action ...

# Release lock, child process going to be finished
lock.release()

2014-07-07

MySQL: UNIQUE KEY + unicode

В прошлой заметке я писал про хранение 4-байтных символов в MySQL и упомянул UTF8MB4, как расширенный вариант UTF8. Оно решает ту задачу, и можно было бы объявить про универсальный и лучший на свете collation, но сегодня я столкнулся с некоторым исключением, которое внесло ложечку дегтя в мои впечатления.

При создании уникального индекса на некое поле с юникодными данными получил ошибку о дублирующихся данных. А ведь их там нет. Проверка показала, что для UTF8MB4 строки "ame", "âme", "Amè", "AMÉ", "ÁME", "Ãme" и "ÂMÈ" одинаковые. Это говорит и SELECT.

Так вот, интересно то, что установив collation в UTF8_BIN я получил нужный результат. Понятное дело, что в этом случае сравнение идет побайтово и всё такое. Фокус в том, что для UTF8MB4_BIN такого эффекта не получаем! Разработчики схитрили или упустили этот момент? Кто знает..

2014-07-01

MySQL: хранение 4-байтных символов юникода

По умолчанию в полях VARCHAR при установленном collation UTF8 не могут храниться строки с символами юникода, состоящими из более чем 3 байт. А такие символы существуют, хоть и не очень часто встречаются. Например "\xf0\x9f\x99\x8e".

Решение в том, чтобы использовать модернизированный collation, UTF8MB4. Просто установите такой на нужной таблице и можно работать. Возможно перед вставкой стоит выполнить команду "SET NAMES UTF8MB4"

P.S. Для поисковиков: "Warning: Incorrect string value"