我在做啥的 Python 多处理进程或池?
Posted
技术标签:
【中文标题】我在做啥的 Python 多处理进程或池?【英文标题】:Python Multiprocessing Process or Pool for what I am doing?我在做什么的 Python 多处理进程或池? 【发布时间】:2013-08-13 03:01:56 【问题描述】:我是 Python 中多处理的新手,并试图弄清楚是否应该使用 Pool 或 Process 来异步调用两个函数。我有两个函数进行 curl 调用并将信息解析为 2 个单独的列表。根据互联网连接,每个功能可能需要大约 4 秒。我意识到瓶颈在于 ISP 连接,多处理不会加快速度,但让它们都启动异步会很好。另外,这对我来说是一个很好的学习经验,可以让我进入 python 的多处理,因为我以后会更多地使用它。
我已阅读 Python multiprocessing.Pool: when to use apply, apply_async or map?,它很有用,但我仍有自己的问题。
所以我可以做到的一种方法是:
def foo():
pass
def bar():
pass
p1 = Process(target=foo, args=())
p2 = Process(target=bar, args=())
p1.start()
p2.start()
p1.join()
p2.join()
我对此实施的疑问是: 1)由于连接阻塞直到调用进程完成......这是否意味着p1进程必须在p2进程启动之前完成?我一直认为 .join() 与 pool.apply() 和 pool.apply_sync().get() 相同,其中父进程在当前运行完成之前无法启动另一个进程(任务)。
另一种选择是:
def foo():
pass
def bar():
pass
pool = Pool(processes=2)
p1 = pool.apply_async(foo)
p1 = pool.apply_async(bar)
我对此实施的疑问是: 1) 我需要 pool.close()、pool.join() 吗? 2) pool.map() 在我得到结果之前会让它们全部完成吗?如果是这样,它们是否仍然异步运行? 3) pool.apply_async() 与使用 pool.apply() 执行每个进程有何不同 4) 这与之前的 Process 实现有何不同?
【问题讨论】:
【参考方案1】:您列出的两个场景完成了相同的事情,但方式略有不同。
第一个场景启动两个单独的进程(称为 P1 和 P2)并启动运行 foo
的 P1 和运行 bar
的 P2,然后等待两个进程完成各自的任务。
第二种情况启动两个进程(称为 Q1 和 Q2),首先在 Q1 或 Q2 上启动 foo
,然后在 Q1 或 Q2 上启动 bar
。然后代码等待,直到两个函数调用都返回。
所以最终结果实际上是相同的,但在第一种情况下,您可以保证在不同的进程上运行 foo
和 bar
。
至于您对并发的具体问题,Process
上的 .join()
方法确实会阻塞,直到进程完成,但是因为您在 P1 和 P2 上都调用了 .start()
(在您的第一个场景中)在加入之前,两个进程将异步运行。但是,解释器会等到 P1 完成后再尝试等待 P2 完成。
对于您关于池方案的问题,您应该在技术上使用pool.close()
,但这取决于您之后可能需要它做什么(如果它超出范围,那么您不必关闭它) . pool.map()
是一种完全不同的动物,因为它将一堆参数(异步)分配给同一个函数,跨池进程,然后等到所有函数调用完成后才返回结果列表。
【讨论】:
对于第一部分,它是否在多个核心上运行该进程?当进程数 > 核心数时会发生什么?【参考方案2】:由于您是从 curl 调用中获取数据,因此您是 IO 绑定的。在这种情况下,grequests 可能会派上用场。这些实际上既不是进程也不是线程,而是协程——轻量级线程。这将允许您发送异步 HTTP 请求,然后使用 multiprocessing.Pool
来加速 CPU 绑定部分。
1) 由于 join 阻塞直到调用进程完成...这是否意味着 p1 进程必须在 p2 进程启动之前完成?
是的,p2.join()
是在 p1.join()
返回的意思之后调用的 p1
已经完成。
1) 我需要一个 pool.close(), pool.join()
如果不执行 close()
和 join()
(如果进程服务不明确),您最终可能会得到孤立的进程
2) pool.map() 在我得到结果之前会让它们全部完成吗?如果是这样,它们是否仍然异步运行?
它们是异步运行的,但 map()
会被阻塞,直到所有任务都完成。
3) pool.apply_async() 与使用 pool.apply() 执行每个进程有何不同
pool.apply()
是阻塞的,所以基本上你会同步处理。
4) 这与之前的 Process 实现有何不同
在您申请 bar
之前,有可能一个工作人员已经完成了 foo
,因此您最终可能会由一个工作人员完成所有工作。此外,如果您的一名工人死亡Pool
会自动生成一个新工人(您需要重新申请该任务)。
总结:我宁愿选择Pool
- 它非常适合生产者-消费者案例,并负责所有任务分配逻辑。
【讨论】:
你确定 p1 进程必须在 p2 进程启动之前完成,因为 join() 吗? bpaste.net/show/ruHgFTAAMkN4UT2INPqu 的输出看起来像在 p2 上在 p1 完成之前开始。 我的意思是,p2
将在 p1
完成加入后加入。我为我的误会道歉。当然,只要适当的start()
返回,这两个进程就会启动。以上是关于我在做啥的 Python 多处理进程或池?的主要内容,如果未能解决你的问题,请参考以下文章