request.urlretrieve 在多处理中 Python 卡住了

request.urlretrieve in multiprocessing Python gets stuck

我正在尝试使用 Python 从 URL 列表下载图像。为了加快处理速度,我使用了多处理库。

我面临的问题是脚本经常 hangs/freezes 自己,我不知道为什么。

这是我正在使用的代码

...
import multiprocessing as mp

def getImages(val):

    #Dowload images
    try:
        url= # preprocess the url from the input val
        local= #Filename Generation From Global Varables And Rand Stuffs...
        urllib.request.urlretrieve(url,local)
        print("DONE - " + url)
        return 1
    except Exception as e:
        print("CAN'T DOWNLOAD - " + url )
        return 0

if __name__ == '__main__':

    files = "urls.txt"
    lst = list(open(files))
    lst = [l.replace("\n", "") for l in lst]

    pool = mp.Pool(processes=4)
    res = pool.map(getImages, lst)

    print ("tempw")

它经常在列表中途卡住(它打印 DONE,或 CAN't DOWNLOAD 到它已处理的列表的一半,但我不知道其余部分发生了什么)。有没有人遇到过这个问题?我已经搜索过类似的问题(例如这个link)但没有找到答案。

提前致谢

您似乎遇到了 GIL 问题:python 全局解释器锁基本上禁止 python 同时执行多个任务。 Multiprocessing 模块实际上是在启动 python 的单独实例以并行完成工作。

但在你的情况下,urllib 在所有这些实例中被调用:它们中的每一个都试图锁定 IO 进程:成功的(例如先来的)给你结果,而其他的(试图锁定一个已经锁定的进程)失败。

这是一个非常简单的解释,但这里有一些额外的资源:

您可以在此处找到另一种并行化请求的方法:Multiprocessing useless with urllib2?

这里有关于 GIL 的更多信息:What is a global interpreter lock (GIL)?

好的,我找到答案了。

一个可能的罪魁祸首是脚本卡在了 URL 的 connecting/downloading 中。所以我添加的是 socket timeout 来限制连接和下载图像的时间。

现在,这个问题不再困扰我了。

这是我的完整代码

...
import multiprocessing as mp

import socket

# Set the default timeout in seconds
timeout = 20
socket.setdefaulttimeout(timeout)

def getImages(val):

    #Dowload images
    try:
        url= # preprocess the url from the input val
        local= #Filename Generation From Global Varables And Rand Stuffs...
        urllib.request.urlretrieve(url,local)
        print("DONE - " + url)
        return 1
    except Exception as e:
        print("CAN'T DOWNLOAD - " + url )
        return 0

if __name__ == '__main__':

    files = "urls.txt"
    lst = list(open(files))
    lst = [l.replace("\n", "") for l in lst]

    pool = mp.Pool(processes=4)
    res = pool.map(getImages, lst)

    print ("tempw")

希望这个解决方案能帮助其他面临同样问题的人