Подтвердить что ты не робот

Когда я должен использовать asyncio для обычных потоков и почему? Увеличивает ли производительность производительность?

У меня есть довольно общее понимание многопоточности в Python и даже базовое понимание asyncio.

В настоящее время я пишу небольшую программу на основе Curses (в конечном счете, буду использовать полный графический интерфейс, но это другая история), которая обрабатывает пользовательский интерфейс и пользовательский интерфейс ввода-вывода в основном потоке, а затем имеет два других потока демона (каждый со своей собственной очереди /worker -method-that-gets-things-from-a-queue):

  • a watcher поток, который следит за событиями, основанными на времени и условном (например, сообщениями на доске сообщений, полученными сообщениями и т.д.), а затем ставит необходимые задачи в...
  • другая (worker) очередь потоков daemon, которая затем завершает их.

Все три потока непрерывно работают одновременно, что приводит к некоторым вопросам:

  • Когда очередь потоков worker (или, в более общем плане, любая очередь потоков) пуста, должна ли она быть остановлена ​​до тех пор, пока не будет что-то делать, или все в порядке, чтобы продолжать работать? Сопутствующие потоки занимают много вычислительной мощности, когда они ничего не делают, кроме наблюдения за своей очередью?
  • Должны ли быть объединены очереди двух потоков? Поскольку поток watcher постоянно работает с одним методом, я думаю, что поток worker мог бы просто вытаскивать задания из одной очереди, в которую помещается поток watcher.
  • Я не думаю, что это будет иметь значение, поскольку я не многопроцессор, но эта настройка зависит от Python GIL (который, как я считаю, все еще существует в версии 3.4)?
  • Должен ли поток watcher работать так непрерывно? Из того, что я понимаю, и, пожалуйста, исправьте меня, если я ошибаюсь, asyncio предполагается использовать для многопоточности на основе событий, что, похоже, имеет отношение к тому, что я пытаюсь сделать.
  • Основной поток в основном всегда просто ждет, пока пользователь нажмет клавишу для доступа к другой части меню. Кажется, что ситуация asyncio была бы идеальной, но, опять же, я не уверен.

Спасибо!

4b9b3361

Ответ 1

Когда очередь рабочего потока (или, в более общем смысле, любая очередь потоков) пуста, следует ли ее остановить, пока не будет что-то делать, или все в порядке, чтобы продолжать работать? Сопутствующие потоки занимают много вычислительной мощности, когда они не делают ничего, кроме наблюдения за своей очередью?

Вы должны использовать блокирующий вызов queue.get(). Это оставит поток заблокированным при вводе-выводе, что означает, что GIL будет выпущен, и никакая вычислительная мощность (или, по крайней мере, минимальная сумма) не будет использоваться. Не используйте неблокирующие элементы в цикле while, так как это потребует намного большего количества пробуждений процессора.

Должны ли быть объединены очереди двух потоков? Поскольку поток наблюдателя постоянно работает с одним методом, я думаю, что рабочий поток сможет просто вытаскивать задания из одной очереди, в которую помещается поток наблюдателя.

Если все наблюдатели делают это, вытягивая вещи из очереди и сразу же помещая их в очередную очередь, где ее потребляет один рабочий, это звучит как ненужные накладные расходы - вы можете просто просто потреблять ее непосредственно у рабочего, Это не совсем ясно для меня, если это случай, однако, является наблюдателем, потребляющим из очереди, или просто помещая элементы в один? Если он потребляет из очереди, кто вкладывает в него материал?

Я не думаю, что это будет иметь значение, поскольку я не многопроцессор, но эта настройка зависит от Python GIL (который, как я считаю, все еще существует в версии 3.4)?

Да, на это влияет GIL. Только один из ваших потоков может запускать байт-код Python за раз, поэтому не будет выполняться true parallelism, за исключением случаев, когда потоки запускают ввод-вывод (который освобождает GIL). Если ваш рабочий поток выполняет операции с привязкой к процессору, вы должны серьезно рассмотреть возможность запуска его в отдельном процессе через multiprocessing, если это возможно.

Должен ли поток наблюдателя работать так непрерывно? Из того, что я понимаю, и, пожалуйста, исправьте меня, если я ошибаюсь, асинчио предполагается использовать для многопоточности на основе событий, что, по-видимому, имеет отношение к тому, что я пытаюсь сделать.

Трудно сказать, потому что я не знаю точно, что означает "работает непрерывно". Что он делает постоянно? Если он тратит большую часть своего времени на сон или блокировку на queue, это прекрасно - обе эти вещи освобождают GIL. Если он постоянно выполняет фактическую работу, это потребует GIL и, следовательно, ухудшает производительность других потоков в вашем приложении (при условии, что они пытаются работать одновременно). asyncio предназначен для программ, которые связаны с I/O, и поэтому их можно запускать в одном потоке с использованием асинхронного ввода-вывода. Похоже, ваша программа может быть хорошо подходит для этого в зависимости от того, что делает ваш worker.

Основной поток в основном всегда просто ждет нажатия на клавишу для доступа к другой части меню. Это похоже на ситуацию, когда асинчио идеально подходит для, но, опять же, я не уверен.

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

Тем не менее, вы вряд ли увидите какое-либо улучшение производительности, переключившись с вашей потоковой программы на что-то на asyncio. Скорее всего, это будет примерно так. Поскольку вы имеете дело только с 3 потоками, накладные расходы на переключение между ними не очень значительны, поэтому переход от того, что однопоточный асинхронный подход ввода-вывода не будет иметь большого значения. asyncio поможет вам избежать сложности синхронизации потоков (если проблема с вашим приложением - неясно, что она есть) и, по крайней мере теоретически, будет лучше масштабироваться, если ваше приложение потенциально нуждается в большом количестве потоков, но это не похоже подобный тот случай. Я думаю для вас, это в основном, к какому стилю вы предпочитаете вводить код (при условии, что вы можете найти все asyncio -собираемые библиотеки, которые вам нужны).