我正在尝试使用多处理运行网络爬虫。我在理解适当数量的池时遇到了一些问题。我应该使用池的数量作为cpu_count()
规范吗?
我的代码是这样的:
def experiment(df,n):
with Pool(n) as p:
results = p.map(ind_scraper_iterator, df)
return(results)
df
是一个字典列表(长度约为 3K(,ind_scraper_iterator
函数使用字典中的字段从 Web 进行查询和抓取。我尝试将n
设置为 600 和 700,但收到错误消息BlockingIOError: [Errno 35] Resource temporarily unavailable
。我收集这是因为池的数量,我想选择适当的数字,这样我就不会被阻止。
在 CPU密集型用例中,是的,您希望池大小不大于可用的 CPU 内核数。如果你在Pool
做 CPU 密集型工作,则不可能并行执行超过cpu_count()
个操作,因为根本没有任何 CPU 可用于执行更多操作。一旦池中的进程数多于CPU 数,实际上最终会损害性能,因为操作系统必须在额外的进程之间进行上下文切换,以便它们都获得一些 CPU 时间,从而增加开销。
您唯一希望Pool
中的进程数超过CPU内核数的情况是,如果您在进程中执行的工作是I/O密集型的,并且大部分时间都在阻塞,等待I/O完成。等待 I/O 不会占用任何 CPU 资源,因此您可以扩展到可用的 CPU 内核数量之外,而不会减少回报。
在您的用例中,您正在进行网络抓取,这确实涉及I/O(从Web获取数据(。我对细节的了解还不够多,无法知道是否有足够的I/O(与您获取数据后正在执行的任何其他操作相比(来证明大于cpu_count()
的池是合理的。您必须进行自己的测试才能找到最佳点。我会说 600-700 个进程可能太多了,仅仅是因为运行一个进程会产生相当多的内存开销,并且可能会使系统过载。如果您的用例严重受 I/O 限制,您可能只想使用线程池,因为 I/O 只需线程即可有效地并行化。只有 CPU 密集型工作不释放 GIL,无法在 (C(Python 中并行化。您可能会发现,序列化少量 CPU 工作最终比并行运行要便宜,但必须处理multiprocessing
引入的进程间通信开销。
与往常一样,您需要进行自己的测试,以确定最适合您的特定用例的测试。