воскресенье, 13 апреля 2014 г.

Оценка производительности aiozmq

Сделал "пузомерку" для сравнения производительности aiozmq и просто pyzmq.

aiozmq использует pyzmq в своих внутренностях и стало интересно узнать, какие тормоза добавляет связка aiozmq + asyncio по сравнению с "простыми zmq сокетами".

Тест делался для пары DEALER/ROUTER (RPC) в разных режимах.

Результаты запуска измерителя производительности:

(aiozmq)andrew@tiktaalik2:~/projects/aiozmq (master)$ python benchmarks/simple.py -n 10000
Run tests for 10*10000 iterations: ['aiozmq.rpc', 'core aiozmq', 'single thread raw zmq', 'single thread zmq with poller', 'zmq with threads']
..................................................

Results for aiozmq.rpc
RPS: 2469,   average: 0.405 ms

Results for core aiozmq
RPS: 5064,   average: 0.197 ms

Results for single thread raw zmq
RPS: 9895,   average: 0.101 ms

Results for single thread zmq with poller
RPS: 12574,  average: 0.080 ms

Results for zmq with threads
RPS: 9702,   average: 0.103 ms

zmq шустрее, естественно. Обработка request-response на zmq в одном потоке примерно вдвое быстрее той же работы, которую делает aiozmq на своих транспортах и протоколах, плюс еще asyncio добавляет тормозов.

Даже на нитях (threads) zmq уверенно побеждает. В этом заслуга libzmq, которая создает свой внутренний thread для обработки send и в результате для Питона send получается неблокирующим.

aiozmq.rpc добавляет тормозов по сравнению с aiozmq.core примерно в два раза. Я считаю это приемлемой платой за прозрачную упаковку/распаковку аргументов вызываемой функции, поиск обработчика на стороне сервера, проверку сигнатур для параметров, пробрасывания исключения назад вызывающей стороне.

Если всю эту необходимую работу сделать на zmq -- думаю, получится не сильно быстрее.

Результат

aiozmq.core дает примерно 5000 requests per second, что довольно неплохо.

aiozmq.rpc способен выжать примерно 2500 rps.

То есть если вас устраивает обработка запроса к aiozmq.rpc меньше чем за одни милисекунду -- aiozmq вам подойдёт.

И, самое главное: если на стороне RPC сервера вы делаете запросы в redis, mongo, postgresql, mysql или обращаетесь каким другим внешним для вашего процесса ресурсам -- скорее всего тормоза будут именно в этом месте.

Почему это не очень важно

Да, я знаю что redis неимоверно быстр: показывает 70000+ rps на простых запросах. Но скорее всего вам таких обращений потребуется несколько, и делать вы их будете из питона используя библиотеку вроде asyncio-redis.

Которая добавляет немало приятных плюшек и расплачивается за это производительностью.

Это не значит что за скорость не нужно бороться. Просто для меня aiozmq показала ожидаемые и вполне неплохие результаты. Самый простой путь к ускорению лежит в оптимизации asyncio путём создания optional C Extensions для event loop и selector. Возможно, я этим займусь, или сделают другие Python Core Developers. Как это произошло с модулем io из стандартной библиотеки: после того как его переписали на С в Python 3.2 получили 30% ускорение.

понедельник, 7 апреля 2014 г.

PyCon RU 2014

Приглашаю всех на PyCon RU 2014.

В прошлом году году конференция прошла просто замечательно!
Интересные доклады и приятное место.

Как и в прошлом году конференция будет в загородном учебном центре Иволга (30 км от Екатеринбурга). Зимой там классно. Уверен, летом не хуже.

Много коллег-питонистов, есть с кем поболтать. Лично для меня это и редкая возможность увидеть тех людей, с которыми знаком больше по переписке, а видимся только на конференциях вроде этой.

Не смотря на то что это аж в Екатиренбурге (далеко от Москвы и близко к географическому центру России) -- рекомендую посетить. О том, как было здорово в прошлый раз повторяться не стану.

Если у кого зудит в ягодицах от желания поделиться новым опытом -- заполните  форму на рассмотрение вашего доклада.

Я тоже приеду с лекцией об asyncio, моём опыте по участии в создании этой системы и написании библиотек для.

Может, будет еще один доклад, пока совершенно секретный (жду согласования).


воскресенье, 6 апреля 2014 г.

aiopg -- asyncio библиотека для PostgreSQL

Сделал библиотеку, которая может работать с PostgreSQL под asyncio.

Внутри используется psycopg2 в асинхронном режиме.

Есть connection pool.

Документация -- здесь.

суббота, 5 апреля 2014 г.

asyncio и HTTP

asyncio не умеет работать с HTTP.

Так и было задумано.

asyncio никогда не станет веб-сервером. Он делался как именно event loop для tcp, ssl, unix sockets, pipes и subprocesses. Плюс streaming API.

Веб был сознательно выпилен и теперь то что было лежит в aiohttp. Эта часть просто не дозрела до включения в стандартную библиотеку.

Идея такая:

  • WSGI -- синхронный протокол, для asyncio не подходит.
  • Какой будет новый стандарт -- неясно никому.
  • Пусть для asyncio люди попытаются сделать свои http либы и время покажет у кого получилось лучше.
  • Тогда, возможно, и появится новый стандарт.

Что касается меня то я пытаюсь понять какой именно должен быть API для HTTP server, что там должно быть обязательно и что нужно сознательно исключить.

Сейчас делаем это aiorest

Когда поймём, что получилось хорошо в aiorest -- займемся перенесением удачных решений в aiohttp. Там HTTP server слишком уж неудобный. А нужно что-то типа tornado.web, но более симпатичное и приятное.

четверг, 3 апреля 2014 г.

aiozmq -- поддержка ZeroMQ сокетов в asyncio

Наверное, уже все слышали про asyncio -- новую стандартную библиотеку для асинхронного сетевого программирования.

Естественно, asyncio не умеет работать с ZeroMQ сокетами и никогда не будет уметь.

На днях я выпустил первую версию библиотеки aiozmq, которая устраняет проблему.

aiozmq предоставляет 0MQ event loop совместимый с asyncio и высокоуровневые средства для организации вызовов удалённых процедур aka RPC.

Если интересны подробности -- читайте документацию, она довольно большая и подробная (постарался).

суббота, 7 сентября 2013 г.

Курсы во Львове

14-15 сентября буду читать немного ужатый вариант курсов по асинхронному сетевому программированию.
Подробности здесь.

суббота, 31 августа 2013 г.

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

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

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

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

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

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

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

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

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

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

threading._shutdown.__self__.ident

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

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