Python 3.x Python多处理池突然停止

Python 3.x Python多处理池突然停止,python-3.x,python-3.6,python-multiprocessing,Python 3.x,Python 3.6,Python Multiprocessing,我正在尝试为我的需求执行并行处理,代码似乎在为4k-5k元素并行工作。但是一旦要处理的元素开始增加,代码就会处理一些列表,然后在不抛出任何错误的情况下,程序就会突然停止运行 我检查了,程序没有挂起,RAM可用(我有一个16 Gb的RAM),CPU利用率甚至不到30%。似乎不知道发生了什么。我有一百万个元素要处理 def get_items_to_download(): #iterator to fetch all items that are to be downloaded y

我正在尝试为我的需求执行并行处理,代码似乎在为4k-5k元素并行工作。但是一旦要处理的元素开始增加,代码就会处理一些列表,然后在不抛出任何错误的情况下,程序就会突然停止运行

我检查了,程序没有挂起,RAM可用(我有一个16 Gb的RAM),CPU利用率甚至不到30%。似乎不知道发生了什么。我有一百万个元素要处理

def get_items_to_download():
    #iterator to fetch all items that are to be downloaded
    yield download_item

def start_download_process():
    multiproc_pool = multiprocessing.Pool(processes=10)
    for download_item in get_items_to_download():
        multiproc_pool.apply_async(start_processing, args = (download_item, ), callback = results_callback)
    
    multiproc_pool.close()
    multiproc_pool.join()

def start_processing(download_item):
    try:
        # Code to download item from web API
        # Code to perform some processing on the data
        # Code to update data into database
        return True
    except Exception as e:
        return False

def results_callback(result):
    print(result)

if __name__ == "__main__":
    start_download_process()
更新-

发现错误-BrokenPipeError:[Errno 32]断开的管道

痕迹-

Traceback (most recent call last):
File "/usr/lib/python3.6/multiprocessing/pool.py", line 125, in worker
put((job, i, result))
File "/usr/lib/python3.6/multiprocessing/queues.py", line 347, in put
self._writer.send_bytes(obj)
File "/usr/lib/python3.6/multiprocessing/connection.py", line 200, in send_bytes
self._send_bytes(m[offset:offset + size])
File "/usr/lib/python3.6/multiprocessing/connection.py", line 404, in _send_bytes
self._send(header + buf)
File "/usr/lib/python3.6/multiprocessing/connection.py", line 368, in _send
n = write(self._handle, buf)
BrokenPipeError: [Errno 32] Broken pipe

代码看起来是正确的。我唯一能想到的是,您的所有进程都在等待完成。这里有一个建议:不要使用
apply\u async
提供的回调机制,而是使用返回的
AsyncResult
对象从流程中获取返回值。您可以在此对象上调用
get
,指定超时值(下面任意指定30秒,可能不够长)。如果任务未在该持续时间内完成,将引发超时异常(如果愿意,您可以捕获它)。但这将检验过程悬而未决的假设。只需确保指定一个足够大的超时值,以便任务能够在该时间段内完成。我还将任务提交分为1000个批次,并不是因为我认为1000000的大小本身就是一个问题,而是因为您没有1000000个结果对象的列表。但是,如果您发现结果不再挂起,那么请尝试增加批处理大小,看看这是否会产生影响

import multiprocessing

def get_items_to_download():
    #iterator to fetch all items that are to be downloaded
    yield download_item

BATCH_SIZE = 1000

def start_download_process():
    with multiprocessing.Pool(processes=10) as multiproc_pool:
        results = []
        for download_item in get_items_to_download():
            results.append(multiproc_pool.apply_async(start_processing, args = (download_item, )))
            if len(results) == BATCH_SIZE:
                process_results(results)
                results = []
        if len(results):
            process_results(results)
    

def start_processing(download_item):
    try:
        # Code to download item from web API
        # Code to perform some processing on the data
        # Code to update data into database
        return True
    except Exception as e:
        return False

TIMEOUT_VALUE = 30 # or some suitable value

def process_results(results):
    for result in results:
        return_value = result.get(TIMEOUT_VALUE) # will cause an exception if process is hanging
        print(return_value)

if __name__ == "__main__":
    start_download_process()
更新

在谷歌上搜索了好几页你的断管错误,你的错误可能是由于耗尽了内存。例如,见。以下返工尝试使用更少的内存。如果有效,您可以尝试增加批次大小:

import multiprocessing


BATCH_SIZE = 1000
POOL_SIZE = 10


def get_items_to_download():
    #iterator to fetch all items that are to be downloaded
    yield download_item


def start_download_process():
    with multiprocessing.Pool(processes=POOL_SIZE) as multiproc_pool:
        items = []
        for download_item in get_items_to_download():
            items.append(download_item)
            if len(items) == BATCH_SIZE:
                process_items(multiproc_pool, items)
                items = []
        if len(items):
            process_items(multiproc_pool, items)


def start_processing(download_item):
    try:
        # Code to download item from web API
        # Code to perform some processing on the data
        # Code to update data into database
        return True
    except Exception as e:
        return False


def compute_chunksize(iterable_size):
    if iterable_size == 0:
        return 0
    chunksize, extra = divmod(iterable_size, POOL_SIZE * 4)
    if extra:
        chunksize += 1
    return chunksize


def process_items(multiproc_pool, items):
    chunksize = compute_chunksize(len(items))
    # you must iterate the iterable returned:
    for return_value in multiproc_pool.imap(start_processing, items, chunksize):
        print(return_value)


if __name__ == "__main__":
    start_download_process()

代码看起来是正确的。我唯一能想到的是,您的所有进程都在等待完成。这里有一个建议:不要使用
apply\u async
提供的回调机制,而是使用返回的
AsyncResult
对象从流程中获取返回值。您可以在此对象上调用
get
,指定超时值(下面任意指定30秒,可能不够长)。如果任务未在该持续时间内完成,将引发超时异常(如果愿意,您可以捕获它)。但这将检验过程悬而未决的假设。只需确保指定一个足够大的超时值,以便任务能够在该时间段内完成。我还将任务提交分为1000个批次,并不是因为我认为1000000的大小本身就是一个问题,而是因为您没有1000000个结果对象的列表。但是,如果您发现结果不再挂起,那么请尝试增加批处理大小,看看这是否会产生影响

import multiprocessing

def get_items_to_download():
    #iterator to fetch all items that are to be downloaded
    yield download_item

BATCH_SIZE = 1000

def start_download_process():
    with multiprocessing.Pool(processes=10) as multiproc_pool:
        results = []
        for download_item in get_items_to_download():
            results.append(multiproc_pool.apply_async(start_processing, args = (download_item, )))
            if len(results) == BATCH_SIZE:
                process_results(results)
                results = []
        if len(results):
            process_results(results)
    

def start_processing(download_item):
    try:
        # Code to download item from web API
        # Code to perform some processing on the data
        # Code to update data into database
        return True
    except Exception as e:
        return False

TIMEOUT_VALUE = 30 # or some suitable value

def process_results(results):
    for result in results:
        return_value = result.get(TIMEOUT_VALUE) # will cause an exception if process is hanging
        print(return_value)

if __name__ == "__main__":
    start_download_process()
更新

在谷歌上搜索了好几页你的断管错误,你的错误可能是由于耗尽了内存。例如,见。以下返工尝试使用更少的内存。如果有效,您可以尝试增加批次大小:

import multiprocessing


BATCH_SIZE = 1000
POOL_SIZE = 10


def get_items_to_download():
    #iterator to fetch all items that are to be downloaded
    yield download_item


def start_download_process():
    with multiprocessing.Pool(processes=POOL_SIZE) as multiproc_pool:
        items = []
        for download_item in get_items_to_download():
            items.append(download_item)
            if len(items) == BATCH_SIZE:
                process_items(multiproc_pool, items)
                items = []
        if len(items):
            process_items(multiproc_pool, items)


def start_processing(download_item):
    try:
        # Code to download item from web API
        # Code to perform some processing on the data
        # Code to update data into database
        return True
    except Exception as e:
        return False


def compute_chunksize(iterable_size):
    if iterable_size == 0:
        return 0
    chunksize, extra = divmod(iterable_size, POOL_SIZE * 4)
    if extra:
        chunksize += 1
    return chunksize


def process_items(multiproc_pool, items):
    chunksize = compute_chunksize(len(items))
    # you must iterate the iterable returned:
    for return_value in multiproc_pool.imap(start_processing, items, chunksize):
        print(return_value)


if __name__ == "__main__":
    start_download_process()

我在Linux上使用Python 3.8时也有过同样的经历。我用
python3.7
multiprocessing.Pool()
建立了一个新的环境,现在可以正常工作了。

我在Linux上使用
python3.8
也有同样的经验。我用
Python 3.7
多处理设置了一个新环境。Pool()
现在可以正常工作了。

我希望您在尝试从同一api并行下载100万个项目之前,已经检查了它们的请求速率限制。是的,我。。这就足够了,如果我只是简单地下载所需的项目,它就可以正常工作,但只要我将processing元素引入multi-processing。然后它开始失败。尝试使用
processs=1
查看它是否仍然失败。16GB对于10个进程来说不算多,您的操作系统可能会杀死一个进程。尝试使用而不是
多处理.Pool
,如果发生这种情况,它将立即中断。还要测试注释掉数据库部分是否有帮助
print()
是您的朋友,请使用它来定位开始挂起的位置。单进程不会发生这种情况。当进程=1时,事情一直顺利进行到最后。你对我下面的回答有什么反馈吗?因为如果你尝试过我的建议,并告诉我发生了什么,我可能会有进一步的建议。例如,您是否发现您确实有挂起但现在超时的任务?或者以1000个批量提交,直到完成(我理解,这是有问题的——如果是这样的话,它应该可以以更大的批量工作)。我希望您在尝试从同一api并行下载100万个项目之前,已经检查了它们的请求速率限制。是的,我。。这就足够了,如果我只是简单地下载所需的项目,它就可以正常工作,但只要我将processing元素引入multi-processing。然后它开始失败。尝试使用
processs=1
查看它是否仍然失败。16GB对于10个进程来说不算多,您的操作系统可能会杀死一个进程。尝试使用而不是
多处理.Pool
,如果发生这种情况,它将立即中断。还要测试注释掉数据库部分是否有帮助
print()
是您的朋友,请使用它来定位开始挂起的位置。单进程不会发生这种情况。当进程=1时,事情一直顺利进行到最后。你对我下面的回答有什么反馈吗?因为如果你尝试过我的建议,并告诉我发生了什么,我可能会有进一步的建议。例如