Поможет ли мне Asyncio? - PullRequest
0 голосов
/ 05 июля 2018

У меня есть небольшое приложение на python, которое я разработал с использованием wxpython4.0.3, которое выполняет довольно простую задачу типа ETL:

  • Принимает пользовательский ввод для выбора родительского каталога, содержащего несколько подкаталоги, полные CSV-файлов (данные временных рядов.)
  • Преобразует данные в каждом из этих файлов в соответствии с форматированием. требуется сторонним получателем и записывает их в новый файлы.
  • Упаковывает каждый новый файл в файл с именем оригинала родительский каталог файла
  • По инициативе пользователя приложение затем отправляет файлы zip по FTP третье лицо, которое будет загружено в хранилище данных.

Приложение работает достаточно хорошо, но время, необходимое для обработки нескольких тысяч CSV-файлов, довольно велико и в основном зависит от ввода-вывода, что я могу сказать.

Является ли Asyncio разумным вариантом или есть другие рекомендации, которые кто-нибудь может дать? Первоначально я написал это как CLI и увидел значительный прирост производительности при использовании pypy, но я не хотел комбинировать pypy с wxpython, когда разрабатывал пользовательский интерфейс для других.

Спасибо за ваше руководство.

Ответы [ 2 ]

0 голосов
/ 05 июля 2018

Если вы заметили значительное ускорение при использовании PyPy вместо CPython, это означает, что ваш код, вероятно, не связан с I / O. Это означает, что асинхронный ввод-вывод не очень поможет. Кроме того, это также будет дополнительной работой, потому что вам придется реструктурировать все ваши загруженные ЦП задачи на маленькие куски, которые могут повторяться await, чтобы они не блокировали другие задачи.

Итак, вы, вероятно, хотите использовать несколько процессов здесь.

Самое простое решение - использовать concurrent.futures.ProcessPoolExecutor: просто бросить задачи исполнителю, и он запустит их на дочерних процессах и вернет вам Future.

В отличие от asyncio, вам не придется менять эти задачи вообще. Они могут читать файл, просто зацикливаясь на модуле csv, обрабатывая все это в одном большом блоке, и даже использовать синхронный модуль ftplib, не беспокоясь о том, что кто-то блокирует кого-то еще. Только ваш код верхнего уровня должен быть изменен.

Однако вы можете рассмотреть возможность разделения кода на wx GUI, который вы запускаете в CPython, и на многопроцессорный движок, который вы запускаете через subprocess в PyPy, который затем выделяет ProcessPoolExecutor в PyPy как Что ж. Это заняло бы немного больше работы, но это означает, что вы получите преимущества от использования PyPy для ЦП, хорошо проверенные преимущества с использованием CPython и параллелизм многопроцессорной обработки.

Другой вариант, который следует рассмотреть, - это использовать библиотеку, такую ​​как NumPy или Pandas, которая может выполнять медленные части (будь то чтение и обработка CSV, или выполнение каких-либо поэлементных вычислений для тысяч строк или что-то еще) быстрее (и возможно, даже выпуская GIL, что означает, что вам не нужна многопроцессорная обработка.


Если ваш код на самом деле является кодом, связанным с вводом / выводом и в первую очередь связанным с запросами FTP, asyncio поможет. Но это потребует переписывания большого количества кода. Вам нужно будет найти или написать клиентскую библиотеку FTP с поддержкой asyncio. И, если чтение файла занимает значительную часть вашего времени, преобразование этого в асинхронное будет еще более трудоемким.

Существует также проблема интеграции цикла событий wx с циклом событий asyncio. Возможно, вам удастся избежать выполнения цикла asyncio во втором потоке, но тогда вам нужно будет найти какой-то способ связи между циклом событий wx в основном потоке и циклом asyncio в фоновый поток. В качестве альтернативы, вы можете использовать один цикл для другого (или даже сторонние библиотеки, которые делают это за вас). Но это может быть намного проще сделать (или иметь более подходящие сторонние библиотеки), например, twisted вместо asyncio.

Но, если вам не нужен массовый параллелизм (чего, вероятно, нет, если у вас нет сотен различных FTP-серверов для общения), потоки должны работать так же хорошо, с гораздо меньшими изменениями в вашем коде. Просто используйте concurrent.futures.ThreadPoolExecutor, что почти идентично использованию ProcessPoolExecutor, как описано выше.

0 голосов
/ 05 июля 2018

Да, вы, вероятно, выиграете от использования асинхронной библиотеки. Поскольку большая часть вашего времени тратится на ожидание ввода-вывода, хорошо написанная асинхронная программа будет использовать это время для выполнения чего-то другого, без дополнительных затрат на потоки / процессы. Это будет очень хорошо масштабироваться.

...