Вам понадобится multiprocessing.Pipe
или multiprocessing.Queue
, чтобы отправить результаты обратно вашему родительскому процессу.Если вы просто делаете I / 0, вы должны использовать Thread
вместо Process
, так как он более легкий и большую часть времени будет тратить на ожидание.Я покажу вам, как это делается для Process и Threads в целом.
Process with Queue
Многопроцессорная очередь построена поверх трубы идоступ синхронизируется с замками / семафорами.Очереди являются поточно-ориентированными и безопасными для процессов, то есть вы можете использовать одну очередь для нескольких процессов производителя / потребителя и даже для нескольких потоков в этих процессах.Добавление первого элемента в очередь также запустит фидерный поток в вызывающем процессе.Дополнительные издержки multiprocessing.Queue
делают использование канала для сценариев одного производителя / одного потребителя предпочтительным и более производительным.
Вот как отправить и получить результат с помощью multiprocessing.Queue
:
from multiprocessing import Process, Queue
SENTINEL = 'SENTINEL'
def sim_busy(out_queue, x):
for _ in range(int(x)):
assert 1 == 1
result = x
out_queue.put(result)
# If all results are enqueued, send a sentinel-value to let the parent know
# no more results will come.
out_queue.put(SENTINEL)
if __name__ == '__main__':
out_queue = Queue()
p = Process(target=sim_busy, args=(out_queue, 150e6)) # 150e6 == 150000000.0
p.start()
for result in iter(out_queue.get, SENTINEL): # sentinel breaks the loop
print(result)
Очередь передается в функцию в качестве аргумента, результаты - .put()
в очереди и родительский get.()
s из очереди..get()
является блокирующим вызовом, выполнение не возобновляется до тех пор, пока не будет получено (указание параметра времени ожидания возможно).Обратите внимание, что sim_busy
выполняет здесь интенсивную работу с процессором, тогда вы выбираете процессы поверх потоков.
Process & Pipe
Для одногоОдного соединения достаточно трубы.Настройка практически идентична, просто методы называются по-разному, и вызов Pipe()
возвращает два объекта подключения.В дуплексном режиме оба объекта имеют конец для чтения и записи, при duplex=False
(симплекс) первый объект соединения является концом чтения канала, а второй - концом записи.В этом базовом сценарии нам просто нужен симплекс-канал:
from multiprocessing import Process, Pipe
SENTINEL = 'SENTINEL'
def sim_busy(write_conn, x):
for _ in range(int(x)):
assert 1 == 1
result = x
write_conn.send(result)
# If all results are send, send a sentinel-value to let the parent know
# no more results will come.
write_conn.send(SENTINEL)
if __name__ == '__main__':
# duplex=False because we just need one-way communication in this case.
read_conn, write_conn = Pipe(duplex=False)
p = Process(target=sim_busy, args=(write_conn, 150e6)) # 150e6 == 150000000.0
p.start()
for result in iter(read_conn.recv, SENTINEL): # sentinel breaks the loop
print(result)
Thread & Queue
Для использования с потоками вы хотите переключиться на queue.Queue
.queue.Queue
строится поверх collections.deque
, добавляя некоторые блокировки, чтобы сделать его поточно-ориентированным.В отличие от очереди и канала многопроцессорной обработки объекты, помещенные в queue.Queue
, не будут подвергаться травлению.Поскольку потоки используют одно и то же адресное пространство памяти, сериализация для копирования в память не требуется, передаются только указатели.
from threading import Thread
from queue import Queue
import time
SENTINEL = 'SENTINEL'
def sim_io(out_queue, query):
time.sleep(1)
result = query + '_result'
out_queue.put(result)
# If all results are enqueued, send a sentinel-value to let the parent know
# no more results will come.
out_queue.put(SENTINEL)
if __name__ == '__main__':
out_queue = Queue()
p = Thread(target=sim_io, args=(out_queue, 'my_query'))
p.start()
for result in iter(out_queue.get, SENTINEL): # sentinel-value breaks the loop
print(result)
- Чтение здесь Почему
for result in iter(out_queue.get, SENTINEL):
следует отдавать предпочтение настройке while True...break
, где это возможно. - Чтение здесь Почему вы должны использовать
if __name__ == '__main__':
во всех ваших сценариях и особенно в многопроцессорной. - Подробнеео
get()
-использовании здесь .