Я пытаюсь понять потоки в Python. Я посмотрел на документацию и примеры, но, честно говоря, многие примеры слишком сложны, и мне трудно их понять.
Как вы четко показываете задачи, разделенные для многопоточности?
Я пытаюсь понять потоки в Python. Я посмотрел на документацию и примеры, но, честно говоря, многие примеры слишком сложны, и мне трудно их понять.
Как вы четко показываете задачи, разделенные для многопоточности?
Ответы:
С тех пор, как этот вопрос был задан в 2010 году, произошло реальное упрощение того, как сделать простую многопоточность с помощью Python с map и pool .
Приведенный ниже код взят из статьи / поста в блоге, который вы обязательно должны проверить (без принадлежности) - Параллелизм в одной строке: лучшая модель для повседневных задач многопоточности . Я подведу итог ниже - это всего лишь несколько строк кода:
Какая многопоточная версия:
Описание
Реализация
multiprocessing.dummy
это то же самое, что и многопроцессорный модуль, но вместо него используются потоки ( важное отличие - использовать несколько процессов для задач, интенсивно использующих процессор; потоки для (и во время) ввода-вывода ):И сроки результатов:
Передача нескольких аргументов (работает так только в Python 3.3 и более поздних версиях ):
Чтобы передать несколько массивов:
Или передать константу и массив:
Если вы используете более раннюю версию Python, вы можете передать несколько аргументов через этот обходной путь ).
(Спасибо user136036 за полезный комментарий.)
источник
with Pool(8) as p: p.map( *whatever* )
и избавляться от бухгалтерских строк тоже.Вот простой пример: вам нужно попробовать несколько альтернативных URL-адресов и вернуть содержимое первого ответа.
Это тот случай, когда многопоточность используется как простая оптимизация: каждая подпоток ожидает разрешения и ответа URL-адреса, чтобы поместить его содержимое в очередь; каждый поток является демоном (не будет поддерживать процесс, если основной поток завершится - это более распространено, чем нет); основной поток запускает все подпотоки, выполняет
get
в очереди ожидание, пока один из них неput
завершит выполнение , затем генерирует результаты и завершает работу (что приводит к удалению любых подпотоков, которые все еще могут выполняться, поскольку они являются потоками демона).Правильное использование потоков в Python неизменно связано с операциями ввода-вывода (поскольку CPython в любом случае не использует несколько ядер для выполнения задач, связанных с ЦП, единственная причина для многопоточности - не блокирование процесса, пока существует ожидание некоторого ввода-вывода ). Между прочим, очереди почти всегда являются лучшим способом перераспределения работы между потоками и / или сбора результатов работы, и они по своей сути поточнобезопасны, поэтому они избавляют вас от беспокойства о блокировках, условиях, событиях, семафорах и других объектах. концепции координации / связи.
источник
join()
метода, поскольку это заставило бы основной поток ждать, пока они не будут выполнены, не потребляя процессор постоянно проверка значения. @ Алекс: спасибо, это именно то, что мне нужно, чтобы понять, как использовать темы.Queue
имя модуля наqueue
. Имя метода такое же.s = q.get()
print s
@ krs013 Вам не нужно,join
потому что Queue.get () блокирует.ПРИМЕЧАНИЕ . Для фактического распараллеливания в Python вы должны использовать многопроцессорный модуль для ветвления нескольких процессов, которые выполняются параллельно (из-за глобальной блокировки интерпретатора потоки Python обеспечивают чередование, но на самом деле они выполняются последовательно, а не параллельно, и только полезно при чередовании операций ввода / вывода).
Однако, если вы просто ищете чередование (или выполняете операции ввода-вывода, которые можно распараллелить, несмотря на глобальную блокировку интерпретатора), то модуль потоков - это то место, с которого нужно начинать. В качестве очень простого примера, давайте рассмотрим проблему суммирования большого диапазона путем суммирования поддиапазонов параллельно:
Обратите внимание, что вышеприведенный пример является очень глупым, поскольку он абсолютно не выполняет ввод-вывод и будет выполняться последовательно, хотя и с чередованием (с дополнительными издержками переключения контекста) в CPython из-за глобальной блокировки интерпретатора.
источник
thread1
выполняется до завершения, пока основной поток блокируется, затем происходит то же самоеthread2
, затем основной поток возобновляет и распечатывает накопленные значения.super(SummingThread, self).__init__()
? Как в stackoverflow.com/a/2197625/806988Как и другие упомянутые, CPython может использовать потоки только для ожидания ввода-вывода из-за GIL .
Если вы хотите использовать несколько ядер для задач, связанных с процессором, используйте многопроцессорность :
источник
f
функции. Параллельно основная программа теперь просто ожидает выхода из процессаjoin
и работает с ним. Если основная часть только что вышла, подпроцесс может завершиться или может не завершиться, поэтомуjoin
всегда рекомендуется делать a .map
функцию, находится здесь: stackoverflow.com/a/28463266/2327328Просто примечание: очередь не требуется для многопоточности.
Это самый простой пример, который я могу себе представить, который показывает 10 процессов, запущенных одновременно.
источник
for
цикле, вы можете вызватьthread.start()
в первом цикле.Ответ от Алекса Мартелли помог мне. Тем не менее, вот модифицированная версия, которая, на мой взгляд, была более полезной (по крайней мере, для меня).
Обновлено: работает как в Python 2, так и в Python 3
источник
import Queue ModuleNotFoundError: No module named 'Queue'
я запускаю python 3.6.5, в некоторых публикациях упоминается, что в python 3.6.5 это так,queue
но даже после его изменения все равно не работаетУчитывая функцию,
f
проделайте это так:Чтобы передать аргументы
f
источник
Thread
объект очищается. Смотрите документы . Существуетis_alive()
метод, который вы можете использовать для проверки потока, если вам нужно.is_alive
метод, но я не мог понять, как применить его к потоку. Я попытался назначить,thread1=threading.Thread(target=f).start()
а затем проверить егоthread1.is_alive()
, ноthread1
он заполненNone
, так что не повезло. Знаете ли вы, есть ли другой способ получить доступ к теме?thread1=threading.Thread(target=f)
затемthread1.start()
. Тогда вы можете сделатьthread1.is_alive()
.thread1.is_alive()
возвратамиFalse
сразу после выхода из функции.Я нашел это очень полезным: создать столько потоков, сколько ядер, и позволить им выполнять (большое) количество задач (в данном случае, вызывая программу оболочки):
источник
В Python 3 есть возможность запуска параллельных задач . Это делает нашу работу проще.
Она имеет пул потоков и процесс объединения .
Следующее дает понимание:
ThreadPoolExecutor Пример ( источник )
ProcessPoolExecutor ( источник )
источник
Использование нового модуля concurrent.futures
Подход к исполнителю может показаться знакомым всем тем, кто раньше запачкал руки в Java.
Также на заметку: чтобы сохранить разумность юниверса, не забывайте закрывать свои пулы / исполнителей, если вы не используете
with
контекст (который настолько хорош, что он делает это для вас)источник
Для меня идеальным примером потоков является мониторинг асинхронных событий. Посмотрите на этот код.
Вы можете поиграть с этим кодом, открыв сеанс IPython и выполнив что-то вроде:
Подожди несколько минут
источник
Большинство документации и учебных пособий используют Python
Threading
иQueue
модуль, и они могут показаться подавляющими для начинающих.Возможно, рассмотрим
concurrent.futures.ThreadPoolExecutor
модуль Python 3.В сочетании с
with
предложением и списком это может быть настоящим шармом.источник
Я видел здесь много примеров, когда никакой реальной работы не выполнялось, и они были в основном связаны с процессором. Вот пример задачи, связанной с процессором, которая вычисляет все простые числа от 10 миллионов до 10,05 миллионов. Я использовал все четыре метода здесь:
Вот результаты на моем Mac OS X четырехъядерном компьютере
источник
if __name__ == '__main__':
перед главным вызовом, в противном случае измерение размножается сам и печатает попытка была сделана начать новый процесс до ... .Вот очень простой пример импорта CSV с использованием потоков. (Включение библиотеки может отличаться для разных целей.)
Вспомогательные функции:
Функция водителя:
источник
Я хотел бы поделиться простым примером и объяснениями, которые я нашел полезными, когда мне пришлось решать эту проблему самостоятельно.
В этом ответе вы найдете некоторую информацию о GIL Python (глобальная блокировка интерпретатора) и простой пример из повседневной жизни, написанный с использованием multiprocessing.dummy, а также несколько простых тестов.
Глобальная блокировка интерпретатора (GIL)
Python не допускает многопоточность в прямом смысле этого слова. Он имеет многопоточный пакет, но если вы хотите многопоточность для ускорения вашего кода, то обычно его не рекомендуется использовать.
У Python есть конструкция, называемая глобальной блокировкой интерпретатора (GIL). GIL гарантирует, что только один из ваших «потоков» может выполняться одновременно. Поток получает GIL, выполняет небольшую работу, а затем передает GIL следующему потоку.
Это происходит очень быстро, поэтому человеческому глазу может показаться, что ваши потоки выполняются параллельно, но на самом деле они просто по очереди используют одно и то же ядро ЦП.
Вся эта передача GIL увеличивает накладные расходы на выполнение. Это означает, что если вы хотите, чтобы ваш код выполнялся быстрее, то использование потокового пакета часто не является хорошей идеей.
Есть причины использовать пакет потоков Python. Если вы хотите запускать некоторые вещи одновременно, а эффективность не имеет значения, тогда это совершенно нормально и удобно. Или, если вы выполняете код, которому нужно что-то ждать (например, какой-то ввод-вывод), тогда это может иметь большой смысл. Но библиотека потоков не позволит вам использовать дополнительные ядра процессора.
Многопоточность может быть передана на аутсорсинг операционной системе (посредством многопроцессорной обработки) и некоторому внешнему приложению, которое вызывает ваш код Python (например, Spark или Hadoop ), или некоторому коду, который вызывает ваш код Python (например: вы могли бы пусть ваш код Python вызывает функцию C, которая выполняет дорогостоящие многопоточные операции).
Почему это важно
Потому что многие люди тратят много времени, пытаясь найти узкие места в своем причудливом многопоточном коде Python, прежде чем узнают, что такое GIL.
Как только эта информация станет понятной, вот мой код:
источник
Вот многопоточность с простым примером, который будет полезен. Вы можете запустить его и легко понять, как многопоточность работает в Python. Я использовал блокировку для предотвращения доступа к другим потокам, пока предыдущие потоки не закончили свою работу. С помощью этой строки кода,
Вы можете разрешить несколько процессов одновременно и удерживать остальные потоки, которые будут выполняться позже или после завершения предыдущих процессов.
источник
Заимствуя из этого поста, мы знаем о выборе между многопоточностью, многопроцессорностью и асинхронностью /
asyncio
и их использованием.В Python 3 есть новая встроенная библиотека для параллелизма и параллелизма: concurrent.futures
Итак, я продемонстрирую в ходе эксперимента, что четыре задачи (то есть
.sleep()
метод) выполняются следующимThreading-Pool
образом:Вывод:
[ ПРИМЕЧАНИЕ ]:
multiprocessing
противthreading
) вы могли бы изменитьThreadPoolExecutor
кProcessPoolExecutor
.источник
Ни одно из предыдущих решений не использовало несколько ядер на моем сервере GNU / Linux (где у меня нет прав администратора). Они просто работали на одном ядре.
Я использовал
os.fork
интерфейс более низкого уровня для порождения нескольких процессов. Это код, который работал для меня:источник
источник