我有一段有用的代码:
def my_map2(func, iterable, processes=None):
''' FASTER THAN mp.Pool() - NOT '''
import multiprocessing as mp # Load multiprocessing library
mp.freeze_support()
if (processes == None):
processes = mp.cpu_count() # Set maximum number of cores?
L = len(iterable)
iter2 = zip(iterable,range(L))
IN = mp.Queue()
for x in iter2:
IN.put(x)
OUT = mp.Queue() # = mp.JoinableQueue() Q3
lock = mp.Lock() # Q2
def target_fun(IN, OUT):
while not IN.empty():
inp = IN.get()
out = (inp[0],func(inp[1]))
with lock: # Q2
OUT.put(out)
proc = [mp.Process(target=target_fun, args=(IN, OUT,)) for x in range(processes)]
for p in proc: p.start() # Run proc
for p in proc: p.join() # Exit the completed proc Q1
results = [OUT.get() for p in range(L)] # Get Results Back Q1
results.sort() # Sort
return( [r[1] for r in results] )
import time
def f(x):
time.sleep(0.1);
return(x)
res = my_map2(f,range(100))
问题:
在从队列中收集之前调用join()。为什么这段代码可以运行?在Queue为空之前调用join(),因此根据文档说明它应该死锁:
任何进程已放入数据的队列必须在加入已将数据放入其中的进程之前耗尽:否则,您将陷入僵局。 但是,如果2行标有' Q1'交换后我们应该遇到一个问题"从一个空队列中获取",但这两个变体看起来都很有效......
如果我删除Lock()(用Q2编辑2行),它确实会出现死锁。为什么现在?
队列是线程和进程安全的。当使用多个进程时,通常使用消息传递来进行进程之间的通信,并避免必须使用任何同步原语(如锁)。 (谈论管道和队列)
JoinableQueue。如果我尝试使用它它不起作用。我尝试了所有:
如果使用JoinableQueue,则必须调用JoinableQueue.task_done()。 如果子进程已将项目放在队列中(并且它没有使用JoinableQueue.cancel_join_thread()),那么在将所有缓冲的项目都刷新到管道之前,该进程将不会终止。
问题3是:那么Normal和Joinable队列之间的实际区别是什么?这是否意味着您可以随时终止在正常队列中放置某些东西的孩子?我以为只有经理程序才能像这样工作...... 另外,那么如何正确使用两个队列?
我已经阅读了库参考资料,相当多的教程和堆栈溢出帖子,但有没有人真正理解这是如何工作的? (谈论join(),不同的Queue类型,何时需要锁定并准确理解后面的过程)