Я хотел бы получить наглядный пример, показывающий разделение задач по нескольким потокам.
Переведено автоматически
Ответ 1
С тех пор, как этот вопрос был задан в 2010 году, произошло реальное упрощение того, как выполнять простую многопоточность в Python с помощью map и pool.
from multiprocessing.dummy import Pool as ThreadPool pool = ThreadPool(4) results = pool.map(my_function, my_array)
Какая многопоточная версия:
results = [] for item in my_array: results.append(my_function(item))
Описание
Map - это классная маленькая функция и ключ к простому внедрению параллелизма в ваш код Python. Для тех, кто не знаком, map - это нечто, заимствованное из функциональных языков, таких как Lisp. Это функция, которая отображает другую функцию поверх последовательности.
Map обрабатывает итерацию последовательности за нас, применяет функцию и сохраняет все результаты в удобном списке в конце.
Реализация
Параллельные версии функции map предоставляются двумя библиотеками: multiprocessing, а также ее малоизвестным, но не менее фантастическим дочерним элементом: multiprocessing.dummy.
multiprocessing.dummy точно такой же, как модуль многопроцессорной обработки, но вместо этого использует потоки (важное различие - используйте несколько процессов для задач с интенсивным использованием ЦП; потоки для (и во время) ввода-вывода):
многопроцессорность.dummy копирует API многопроцессорной обработки, но является не более чем оболочкой вокруг модуля многопоточности.
import urllib2 from multiprocessing.dummy import Pool as ThreadPool
for u in theurls: t = threading.Thread(target=get_url, args = (q,u)) t.daemon = True t.start()
s = q.get() print s
Это случай, когда потоковая обработка используется как простая оптимизация: каждый подпоток ожидает разрешения URL-адреса и ответа, чтобы поместить его содержимое в очередь; каждый поток является демоном (не будет поддерживать процесс, если основной поток завершается - это чаще, чем нет); основной поток запускает все подпотоки, выполняет get в очереди, чтобы дождаться, пока один из них не выполнит put, затем выдает результаты и завершается (что отключает любые подпотоки, которые могли бы все еще работают, поскольку это потоки демонов).
Правильное использование потоков в Python неизменно связано с операциями ввода-вывода (поскольку CPython в любом случае не использует несколько ядер для выполнения задач, связанных с ЦП, единственная причина потоковой обработки - это не блокировка процесса во время ожидания некоторого ввода-вывода). Очереди почти всегда являются лучшим способом передачи работы потокам и / или сбора результатов работы, кстати, и они по сути потокобезопасны, поэтому избавляют вас от беспокойства о блокировках, условиях, событиях, семафорах и других концепциях межпотоковой координации / коммуникации.
Ответ 3
ПРИМЕЧАНИЕ: Для фактического распараллеливания в Python вам следует использовать модуль многопроцессорности для разветвления нескольких процессов, которые выполняются параллельно (из-за глобальной блокировки интерпретатора потоки Python обеспечивают чередование, но фактически они выполняются последовательно, а не параллельно, и полезны только при чередовании операций ввода-вывода).
Однако, если вы просто ищете чередование (или выполняете операции ввода-вывода, которые могут быть распараллелены, несмотря на глобальную блокировку интерпретатора), то начать стоит с модуля многопоточность. В качестве действительно простого примера давайте рассмотрим проблему суммирования большого диапазона путем параллельного суммирования поддиапазонов:
defrun(self): for i inrange(self.low,self.high): self.total+=i
thread1 = SummingThread(0,500000) thread2 = SummingThread(500000,1000000) thread1.start() # This actually causes the thread to run thread2.start() thread1.join() # This waits until the thread has completed thread2.join() # At this point, both threads have completed result = thread1.total + thread2.total print result
Обратите внимание, что приведенный выше пример является очень глупым, поскольку он не выполняет абсолютно никакого ввода-вывода и будет выполняться последовательно, хотя и с чередованием (с дополнительными накладными расходами на переключение контекста) в CPython из-за глобальной блокировки интерпретатора.
Ответ 4
Как и другие упомянутые, CPython может использовать потоки только для ожидания ввода-вывода из-за GIL.
Если вы хотите использовать несколько ядер для задач, связанных с ЦП, используйте многопроцессорность:
from multiprocessing import Process
deff(name): print'hello', name
if __name__ == '__main__': p = Process(target=f, args=('bob',)) p.start() p.join()