池处理使用异步内存泄漏

时间:2021-07-21 21:05:01

标签: python pandas multithreading multiprocessing threadpool

我的代码需要一些帮助,我正在尝试使用池来运行我的列表中的一些函数。

这是一个包含大量数据的文件。比如 71GB 的文本。

我正在尝试尽快越线。 但是由于某种原因,在运行过程中,我因内存不足而被杀死

我认为这是因为我的 pool.close 和 pool.join 在我的代码末尾。

但我不知道如何修复它以避免内存泄漏。我认为我的过程永远不会停止并保存数据。

注意:api.delete_object(item) 返回大量数据。也许它以某种方式卡在内存中?

这是我的代码:

import pandas as pd
import boto3
from multiprocessing.pool import ThreadPool as Pool

pool_size = 8  # my "parallelness"


def worker(item):
    try:
        result = api.delete_object(item)
    except:
        print('error with item')

pool = Pool(pool_size)        
i=0
for chunk in pd.read_csv("/folder/files_to_delete",chunksize=1000,header=None):
            i+=1000
            for ind in chunk.index:
              if "something.txt" not in chunk[0][ind]:
                    pool.apply_async(worker, (chunk[0][ind],))
                    print("{}".format(i), end='\r')
pool.close()
pool.join()

1 个答案:

答案 0 :(得分:0)

尽管您使用 multiprocessing 标记了您的问题,但您使用的是多线程。但在我看来,使用多处理可能会更好,因为我不清楚使用线程执行 api.delete_object(item) 可以实现多少“并行”。

无论如何,您可以尝试重新排列代码以使用函数 imap_unordered,然后迭代它返回的 iterable。虽然您的工作函数 worker 的返回值不是特别有趣(发布的工作函数仅返回 None,但这也许是一种简化),检索这些值应该释放正在曾经拿着它们。

import pandas as pd
import boto3
from multiprocessing.pool import ThreadPool as Pool

def generate_arguments():
    i = 0
    with pd.read_csv("/folder/files_to_delete",chunksize=1000,header=None) as rdr:
        for chunk in rdr:
            i += 1000
            for ind in chunk.index:
                if "something.txt" not in chunk[0][ind]:
                    yield chunk[0][ind]
                    print("{}".format(i), end='\r')
        

def worker(item):
    try:
        result = api.delete_object(item)
    except:
        print('error with item')

def main():
    pool_size = 8  # my "parallelness"
    pool = Pool(pool_size)
    results = pool.imap_unordered(worker, generate_arguments())
    # You can iterate results to get return values, which are None, from worker function:
    for result in results:
        # result is return value from worker
        pass
    pool.close()
    pool.join()

if __name__ == '__main__':
    main()

如果您确实切换到多处理,您应该在调用 imap_unordered 时指定一个 chunksize 参数。我建议您估算将提交的任务数量并除以 4 * 池大小,并将结果用作该值。例如,如果您估计将提交 200,000 个任务并且池大小为 8,则使用 chunksize200_000 / (4 * 8) = 6250

请注意,imap_unordered 可以以任意顺序返回结果,但比 imap 更有效。如果您实际上是从 worker 返回的不是 None 并且需要结果按照任务提交的顺序,那么使用方法 imap 或让 imap_unordered 额外返回其传递参数。