为什么 "multiprocessing.Pool" 运行 没完没了 Windows?

Why does "multiprocessing.Pool" run endlessly on Windows?

我已经定义了函数 get_content 以从 https://www.investopedia.com/ 抓取数据。我试过 get_content('https://www.investopedia.com/terms/1/0x-protocol.asp') 并且成功了。然而,这个过程似乎在我的 Windows 笔记本电脑上 运行 无限。我检查过它 运行 在 Google Colab 和 Linux 笔记本电脑上运行良好。

能否请您详细说明为什么我的功能在此并行设置中不起作用?

import requests
from bs4 import BeautifulSoup
from multiprocessing import dummy, freeze_support, Pool
import os
core = os.cpu_count() # Number of logical processors for parallel computing
headers = {'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0'}
session = requests.Session() 
links = ['https://www.investopedia.com/terms/1/0x-protocol.asp', 'https://www.investopedia.com/terms/1/1-10net30.asp']

############ Get content of a word
def get_content(l):
    r = session.get(l, headers = headers)
    soup = BeautifulSoup(r.content, 'html.parser')
    entry_name = soup.select_one('#article-heading_3-0').contents[0]
    print(entry_name)

############ Parallel computing 
if __name__== "__main__":
    freeze_support()
    P_d = dummy.Pool(processes = core)
    P = Pool(processes = core)   
    #content_list = P_d.map(get_content, links)
    content_list = P.map(get_content, links)

Update1: 我 运行 此代码在来自 Anaconda 发行版的 JupyterLab 中。从下面的屏幕截图可以看出,状态一直是 busy

Update2:代码在Spyder中可以执行完毕,但是还是returns没有输出。

更新 3: 代码 运行 在 Colab 中完全没问题:

这里要解压缩很多,但基本上都归结为 python 如何启动一个新进程,并执行您想要的功能。

在 *nix 系统上,创建新进程的默认方法是使用 fork. This is great because it uses "copy-on-write" to give the new child process access to a copy of the parent's working memory. It is fast and efficient, but it comes with a significant drawback if you're using multithreading at the same time. Not everything actually gets copied, and some things can get copied in an invalid state (threads, mutexes, file handles etc). This can cause quite a number of problems if not handled correctly, and to get around those python can use spawn 代替(另外 Windows 没有“fork”并且 must 使用 "spawn").

Spawn 基本上是从头开始一个新的解释器,不会以任何方式复制父进程的内存。然而,必须使用某种机制让子进程访问在创建之前定义的函数和数据,python 通过让新进程基本上 import * 来自它创建的“.py”文件来做到这一点从。 这对于交互模式是有问题的,因为 import 并没有真正的“.py”文件,并且是 “多处理不喜欢交互”的主要来源。 =42=] problems. 将你的 mp 代码放入库中,然后导入并执行 does 在交互中工作,因为它 can 从“.py”文件导入。这也是为什么我们使用 if __name__ == "__main__": 行来分隔您不希望在导入发生时在子项中重新执行的任何代码。如果你要在没有这个的情况下生成一个新进程,它可以递归地继续生成子进程(尽管在技术上有一个针对特定情况的内置保护 iirc)。

然后使用任一启动方法,父级通过 pipe 与子级通信(使用 pickle 交换 python 对象)告诉它调用什么函数,以及论点是。这就是参数必须是可腌制的原因。 有些东西不能 pickle,这是 multiprocessing 中另一个常见的错误来源。

最后一点,IPython 解释器(默认的 Spyder shell)在使用“spawn”时并不总是从子进程收集 stdout 或 stderr,意思是 print不会显示语句。香草 (python.exe) 解释器处理得更好。

在您的具体情况下:

  • Jupyter 实验室 运行 处于交互模式,子进程将被创建但出现类似“无法从 __main__ 导入 get_content”的错误。该错误没有正确显示,因为它没有发生在主进程中,并且 jupyter 没有正确处理来自子进程的 stderr
  • Spyder 使用 IPython,默认情况下不会将 print 语句从子级中继到父级。在这里你可以切换到“运行”对话框中的“外部系统控制台”,但是你还必须做一些事情来保持 window 打开足够长的时间来读取输出(防止进程退出).
  • Google Colab 使用 google 服务器 运行ning Linux 来执行您的代码,而不是在您的 windows 机器上本地执行,所以通过使用“fork”作为开始方法,import 没有“.py”文件的特殊问题不是问题。