Архив метки: Python

Определение главного потока приложения

В многопоточной программе все потоки равны, но один всё же несколько выделяется. Это — главный поток.

Главным потоком называется тот, который создаётся при запуске процесса операционной системой. Потом программа может наплодить себе разных потоков на собственные нужды, но главный есть всегда.

Иногда нужно знать, код исполняется в главном потоке или нет. Например, работать с UNIX сигналами можно только из главного потока. Различные GUI библиотеки часто тоже хотят выполняться непременно в главном потоке и никаком другом.

Если мы пишем приложение, то всегда можно придумать тот или иной способ узнать главный поток. Например, при старте, когда других потоков ещё нет, узнать идентификатор потока через threading.get_ident() и запомнить его где-нибудь.

Когда создаём библиотеку такой способ не всегда подходит. А в самом питоне нет официального способа определить, главный поток это или нет.

Зато работают пара хаков.

Тест на главность потока:

isinstance(threading.current_thread(), threading._MainThread)

Идентификатор главного потока:

threading._shutdown.__self__.ident

Используются непубличные механизмы, но это всё же лучше чем ничего.

P.S. В Python 3.4 появится функция threading.main_thread(), которая возвращает объект главного потока. А до тех пор пользуемся хаками.

Автор: Andrew Svetlov

Celery, начало работы

Данное сообщение является одним из многих, которые будут написаны в процессе изучения Celery.

Celery — «distributed task queue». Это распределенная асинхронная очередь заданий, которая обладает широким функционалом.

Celery умеет:

  • Выполнять задания асинхронно или синхронно
  • Выполнять периодические задания(умная замена crond)
  • Выполнять отложенные задания
  • Распределенное выполнение (может быть запущен на N серверах)
  • В пределах одного worker'а возможно конкурентное выполнение нескольких задач(одновременно)
  • Выполнять задание повторно, если вылез exception
  • Ограничивать количество заданий в единицу времени(rate limit, для задания или глобально)
  • Routing заданий(какому worker'у что делать)
  • Несложно мониторить выполнение заданий
  • Выполнять подзадания
  • Присылать отчеты об exception'ах на email
  • Проверять выполнилось ли задание(удобно для построения Ajax приложений, где юзер ждет факта завершения)

Для использования нужно

 >>> from celery import Celery
>>> celery = Celery()
>>> celery

 В последней строке показано имя класса Celery, имя текущего основного модуля (__main__) и адреса памяти объекта (0x100469fd0).

Всякий раз при добавлении задания, задание добавляется в локальный реестр.

Варианты использования:

  • если задача оформлена как модуль, то запускается как программа,
  •  

Автор: D1VER
Дата публикации: 2013-08-29T01:18:00.000-07:00

Celery для веб-сервисов. Асинхронное распределенное выполнение задач

Докладчик: Роман Иманкулов, NetAngels
Инфраструктура HTTP не предполагает долгих раздумий веб-сервера. Когда необходимо выполнить тяжелую работу без ухудшенияuser experience и снижения надежности системы, возникает потребность в организации очередей команд. В докладе мы рассмотрим вариантыорганизации таких очередей подручными средствами, выясним, чем так хорош Celery, как его можно подключить к вашему проекту, и о чем нужнопомнить программистам и администраторам при его использовании. В заключении рассмотрим возможность выполнения произвольнойпоследовательности команд в бекграунде с использованием celery-tasktree.

Автор: D1VER
Дата публикации: 2013-08-26T02:37:00.002-07:00

Опыт просветления: bash и Python

Не один год работая с Python и bash я, главным образом, использовал

  • первый — для написания программ,
  • второй — для выполнения команд ОС.

При этом моя работа в интерактивном режиме Python сводилась к маленьким исследованиям того, как работает некий фрагмент кода. А в командной строке bash я не пользовался конструкциями, присущими языкам программирования, такими, как if или for, ограничиваясь запуском отдельных команд. Читать →

WSGI — приложения

WSGI — приложения

Вот пример простейшего WSGI приложения:

def MyApplication(environ, start_response):
     start_response('200 OK', [('Content-type', 'text/plain')])
     yield «Hello, world!»

Помимо yield можно делать return(это основной способ) и print(если позволяет веб-сервер). Обратите внимание, что Apache mod_wsgi запрещает использовать поток вывода, поэтому любая попытка сделать print будет приводить к ошибке.

Давайте теперь разберём по порядку.

Первое, что делает наше приложение, это start_response — эта функция сообщает веб-серверу статус и http-заголовки. Загоовки передаются в виде массива, каждый элемент которого представляет из себя tuple с двумя полями. Первое поле — название заголовка, второе — значение. Соответсвенно, так же передаются и куки.

Затем, мы возвращает результат веб-серверу. Делается это с помощью yield или return. Главное, чтобы возвращаемый объект был итератором. Т.е. вы можете сами определить возвращаемый объект, но как правило используются простые массивы.

Как сделать выдачу в реальном времени

Допустим, на вашем сайте есть такие страницы, расчёт выдачи которых занимает много времени, но вы не хотите заставлять пользователя смотреть в пустую страницу, пока идёт обработка запроса. Для сглаживания таких моментов можно применить следующий способ:

  • Определяете свой собственный класс, делаете этот класс итератором, т.е. определяете методы __iter__() и next()
  • Метод next() переопределяете таким образом, что в нём будет происходить вся обработка запроса. Результаты обработки возвращаются с помощью yield.

Допустим, вы хотите вернуть шапку вашего сайта, тогда вы делаете yield «html-текст вашей шапки» а затем вы обрабатываете запрос дальше и следующий ответ снова выводите через yield.

Пример

Вот простой пример, как сделать выдачу в реальном времени.

class Response()
    def __iter__(self):
        return self
    def next(self):
        «тут начинаем обработку запроса»
        «когда нам уже есть что показать, отдаём ответ»
        yield «Hello»
        «Продолжаем обрабатывать запрос»
        «Допустим, делаем какие-то ресурсоёмкие операции»
        «Когда нам снова есть что отдавать, отдаём»
        yield «World»
        «Ну, теперь мы можем выводит остальную часть страницы»
        yield «!!!»
        «Чтобы остановить итерацию, надо вызвать исключение»
        raise StopIteration

Само WSGI-приложение теперь будет выглядеть вот так:

def Application(environ,start_response):
    answer=Response()
    start_response('200 OK',[(«Content-type»,»text/html»)])
    return answer

Автор: D1VER
Дата публикации: 2013-08-18T09:32:00.000-07:00

Запуск процессов в tulip

В последнее время я работаю над запуском процессов в tulip: PEP 3156 и реализация на гуглокоде

Состояние дел на сегодня

Базовые конструкции выглядят так:

Транспорт:

class BaseTransport:
"""Base ABC for transports."""

def get_extra_info(self, name, default=None):
"""Get optional transport information."""

def close(self):
"""Closes the transport.

Buffered data will be flushed asynchronously. No more data
will be received. After all buffered data is flushed, the
protocol's connection_lost() method will (eventually) called
with None as its argument.
"""

class SubprocessTransport(BaseTransport):

def get_pid(self):
"""Get subprocess id."""

def get_returncode(self):
"""Get subprocess returncode.

See also
http://docs.python.org/3/library/subprocess#subprocess.Popen.returncode
"""

def get_pipe_transport(self, fd):
"""Get transport for pipe with number fd."""

def send_signal(self, signal):
"""Send signal to subprocess.

See also:
http://docs.python.org/3/library/subprocess#subprocess.Popen.send_signal
"""

def terminate(self):
"""Stop the subprocess.

Alias for close() method.

On Posix OSs the method sends SIGTERM to the subprocess.
On Windows the Win32 API function TerminateProcess()
is called to stop the subprocess.

See also:
http://docs.python.org/3/library/subprocess#subprocess.Popen.terminate
"""

def kill(self):
"""Kill the subprocess.

On Posix OSs the function sends SIGKILL to the subprocess.
On Windows kill() is an alias for terminate().

See also:
http://docs.python.org/3/library/subprocess#subprocess.Popen.kill
"""

Протокол:

class BaseProtocol:
"""ABC for base protocol class.

Usually user implements protocols that derived from BaseProtocol
like Protocol or ProcessProtocol.

The only case when BaseProtocol should be implemented directly is
write-only transport like write pipe
"""

def connection_made(self, transport):
"""Called when a connection is made.

The argument is the transport representing the pipe connection.
To receive data, wait for data_received() calls.
When the connection is closed, connection_lost() is called.
"""

def connection_lost(self, exc):
"""Called when the connection is lost or closed.

The argument is an exception object or None (the latter
meaning a regular EOF is received or the connection was
aborted or closed).
"""

class SubprocessProtocol(BaseProtocol):
"""ABC representing a protocol for subprocess calls."""

def pipe_data_received(self, fd, data):
"""Called when subprocess write a data into stdout/stderr pipes.

fd is int file dascriptor.
data is bytes object.
"""

def pipe_connection_lost(self, fd, exc):
"""Called when a file descriptor associated with the child process is
closed.

fd is the int file descriptor that was closed.
"""

def process_exited(self):
"""Called when subprocess has exited.
"""

Нужные методы в event loop:

class AbstractEventLoop:
"""Abstract event loop."""

def subprocess_shell(self, protocol_factory, cmd, *, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
**kwargs):
"""Run cmd in shell"""

def subprocess_exec(self, protocol_factory, *args, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
**kwargs):
"""Subprocess *args"""

Т.е. интерфейс запуска процесса почти повторяет subprocess.Popen за исключением того, что subprocess.PIPE теперь вариант по умолчaнию. Заодно еще избавляемся от кошмара с правильным использованием shell=True (см. пост на эту тему). Поддерживаются только байтовые потоки, как и везде в tulip.

Оно уже в целом работает на Unix, код для Windows тоже готовится.

Делает всё что можно и нужно за исключением TTY. C TTY ван Россум предложил пока не связываться, да и subprocess его не поддерживает.

Проблема

Рабочие транспорты и протоколы — это, конечно, классно. Вполне подходящий низкоуровневый строительный блок.

Но простому программисту хочется иметь что-то более удобное и привычное.

Для tulip это должен быть код на основе yield from.

Проблема в том, что для процессов мы имеем не один поток ввода-вывода, а три однонаправленных: stdin, stdout и stderr. А еще процесс может сам решить закрыться, и это тоже нужно удобно обрабатывать.

Просьба

Я пытался придумать что-то такое, но результат пока мне не нравится.

Может, кто сумеет посоветовать дельную конструкцию? Или указать на готовую библиотеку, у которой можно поучиться?

Автор: Andrew Svetlov