Python: когда использовать Threads или Multiprocessing

Каковы некоторые хорошие рекомендации, которые следует учитывать при принятии решения об использовании потоков или многопроцессорности, если говорить с точки зрения эффективности и ясности кода?

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

Для CPython я бы использовал модуль multiprocessing в следующих случаях:

  • Мне нужно использовать несколько ядер одновременно по соображениям производительности. Глобальная блокировка интерпретатора (GIL) предотвратит любое ускорение при использовании потоков. (Иногда в любом случае вы можете уйти с потоками, например, когда основная работа выполняется в C-коде, вызываемом через ctypes или при использовании Cython, и явным образом освобождая GIL, где он работает. Конечно, последнее требует особой осторожности.) Обратите внимание, что этот случай на самом деле довольно редок. Большинство приложений не ограничены временем процессора, и, если они действительно есть, вы обычно не используете Python.

  • Я хочу превратить свое приложение в настоящее приложение. Это намного проще сделать для многопроцессорного приложения.

  • Между задачами, которые необходимо выполнить, требуется очень мало общего состояния.

Почти во всех других случаях я бы использовал потоки. (Это включает в себя работу с графическими приложениями.)

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

Я искал некоторые достойные примеры Queue, и у этого есть некоторые отличные примеры того, как их использовать и насколько они полезны (с той же логикой, применяемой для очереди многопроцессорности): http://effbot.org/librarybook/ queue.htm

Для эффективности детали и результаты могут заметно не повлиять на большинство людей, но для python <= 3.1 реализация CPython имеет некоторые интересные (и потенциально жестокие) проблемы с эффективностью многоядерных машин, о которых вы, возможно, захотите узнать. Эти проблемы связаны с GIL . Дэвид Бэзли сделал видео-презентацию на некоторое время назад, и это определенно стоит посмотреть. Более подробная информация здесь , в том числе последующая информация о значительных улучшениях на этом фронте в python 3.2.

В принципе, мое дешевое резюме многоядерной проблемы, связанной с GIL, заключается в том, что если вы ожидаете получить полное многопроцессорное использование из CPython <= 2.7 с помощью нескольких потоков, не удивляйтесь, если производительность не велика или даже хуже чем одноядерный. Но если ваши потоки выполняют кучу ввода / вывода (чтение / запись файлов, доступ к БД, чтение / запись сокетов и т. Д.), Вы можете даже не заметить проблему.

Модуль многопроцессорности полностью устраняет эту потенциальную проблему GIL, создавая интерпретатор python (и GIL) для каждого процессора.