пятница, 3 июня 2011 г.

pyflowctrl: увеличение производительности

Изначально, при разработке концепции работы pyflowctrl вопрос производительности остро не стоял. Важно было проверить на практике, что сама по себе идея рабочая. Сейчас пришло время уделить больше внимания производительности, выявить узкие места, влияющих на время выполнения скриптов, использующих pyflowctrl.

В качестве эталона для сравнения воспользуемся простым кодом perfcheck.py, который выполняет те же действия, что и пример из поста “pyflowctrl: управление процессами в python”.


for i in xrange(10**6):
    print i + 100,

На базе pyflowctrl этот же код представлен в виде трех процессов: генератор целых чисел, процесс для добавления 100, процесс для вывода результата на экран

Сравним время выполнения
$ time python perfcheck.py > /dev/null

real    0m0.681s
user    0m0.660s
sys    0m0.010s

$ time python examples/example1.py > /dev/null

real    0m11.522s
user    0m11.450s
sys    0m0.020s

Код на основе pyflowctrl выполняется в 17 раз медленнее. Это естественно, что такой временной отрыв существует и будет сущестовать. Код, использующий pyflowctrl никогда не будет работать с такой же производительностью как и эталонный. Вопрос в том, можно ли улучшить показатели, и снизить время выполнения?

pyflowctrl создавался как инструмент для связи различных компонент/процессов в единую программу, поэтому необходимо проверить как расходуется время при передаче данных от одного процесса другому.

Изобразим на диаграмме обобщенную схему взаимодействия процессов:

Время выполнения можно разделить на этапы:
- извлечение данных из входного потока
- выполнение логики процесса
- размещение результатов в выходной поток
- передача данных между потоками

За передачу данных между процессами отвечает отдельный код, который переносит данные из одного потока в другой. Если воспользоваться методами из поста “Работаем с ссылками на словари в python” от кода для передачи данных между процессами можно вообще отказаться и тем самым сократить время выполнения.

Идея состоит в том, что при соединении двух процессов выходной и входной потоки процессов объединяются и используются как один общий поток. Это достигается благодаря тому, что при присвоении переменной значения, ей передается ссылка на объект, а не копия объекта. Различные переменные могут оперировать одним и тем же объектом.

Примечание: Более подробно о работе ссылками на объекты в python можно прочесть так же в “Тождественность в python на примере списков”

Подход c объединением потоков схематически можно изобразить следующим образом:
Новая версия ядра pyflowctrl core2.py и тестового скрипта core2.test.py доступна в репозитории sources-ownport

Сравним время выполнения:
$ time python examples/example2.py > /dev/null

real    0m6.520s
user    0m6.500s
sys    0m0.010s
Прогресс достигнут, время выполнения сокращено в 1.8 раза. Данный подход не только позволил повысить производительность, но и сократить размер кода.

0 комментариев:

Отправить комментарий