繁体   English   中英

如何将结果从Multiprocessing.Pool流到csv?

[英]How to stream results from Multiprocessing.Pool to csv?

我有一个带键的python进程(2.7),进行一堆计算并返回结果列表。 这是一个非常简化的版本。

我正在使用多处理来创建线程,以便可以更快地处理它。 但是,我的生产数据有几百万行,每个循环需要花费更长的时间才能完成。 我上次运行该循环的时间超过了6分钟,而在开始时则花费了一秒钟或更短的时间。 我认为这是因为所有线程都将结果添加到结果集中,并且一直持续增长,直到包含所有记录为止。

是否可以使用多重处理将每个线程(列表)的结果流式传输到csv或批处理结果集中,以便在设置一定数量的行之后将其写入csv?

对于加快或优化该方法的任何其他建议将不胜感激。

import numpy as np
import pandas as pd
import csv
import os
import multiprocessing
from multiprocessing import Pool

global keys
keys = [1,2,3,4,5,6,7,8,9,10,11,12]

def key_loop(key):
    test_df = pd.DataFrame(np.random.randn(1,4), columns=['a','b','c','d'])
    test_list = test_df.ix[0].tolist()
    return test_list

if __name__ == "__main__":
    try:
        pool = Pool(processes=8)      
        resultset = pool.imap(key_loop,(key for key in keys) )

        loaddata = []
        for sublist in resultset:
            loaddata.append(sublist)

        with open("C:\\Users\\mp_streaming_test.csv", 'w') as file:
            writer = csv.writer(file)
            for listitem in loaddata:
                writer.writerow(listitem)
        file.close

        print "finished load"
    except:
        print 'There was a problem multithreading the key Pool'
        raise

这是巩固我和伊芙提出的建议的答案

import numpy as np
import pandas as pd
import csv
from multiprocessing import Pool

keys = [1,2,3,4,5,6,7,8,9,10,11,12]

def key_loop(key):
    test_df = pd.DataFrame(np.random.randn(1,4), columns=['a','b','c','d'])
    test_list = test_df.ix[0].tolist()
    return test_list

if __name__ == "__main__":
    try:
        pool = Pool(processes=8)      
        resultset = pool.imap(key_loop, keys, chunksize=200)

        with open("C:\\Users\\mp_streaming_test.csv", 'w') as file:
            writer = csv.writer(file)
            for listitem in resultset:
                writer.writerow(listitem)

        print "finished load"
    except:
        print 'There was a problem multithreading the key Pool'
        raise

同样,这里的变化是

  1. 直接遍历resultset ,而不是不必要地首先将其复制到列表中。
  2. keys列表直接输入pool.imap而不是根据它创建生成器理解。
  3. 提供了一个更大的chunksizeimap比1.较大的默认chunksize减少了内部传递值所需要的进程间通信的成本keys在你池中的子过程,它可以给大的性能提升时, keys非常大(视您的情况而定)。 你应该有不同的价值观实验chunksize (尝试比200大很多的东西,像5000等等),看看它是如何影响性能。 我对200进行了一个疯狂的猜测,尽管它肯定比1更好。

以下非常简单的代码将许多工作人员的数据收集到一个CSV文件中。 工作人员获取密钥并返回行列表。 父级使用多个工作程序一次处理多个密钥。 完成每个键后,父级将输出行按顺序写入CSV文件。

注意订购。 如果每个工作人员都直接写入CSV文件,那么他们将陷入混乱或彼此脚。 让每个工作人员写入自己的CSV文件很快,但是随后需要将所有数据文件合并在一起。

资源

import csv, multiprocessing, sys

def worker(key):
    return [ [key, 0], [key+1, 1] ]


pool = multiprocessing.Pool()   # default 1 proc per CPU
writer = csv.writer(sys.stdout)

for resultset in pool.imap(worker, [1,2,3,4]):
    for row in resultset:
        writer.writerow(row)

产量

1,0
2,1
2,0
3,1
3,0
4,1
4,0
5,1

我敢打赌,使用追加立即处理大型结构的原因是它使速度变慢。 我通常要做的是打开与核心一样多的文件,并使用modulo立即写入每个文件,这样,与将它们全部定向到同一文件(写入错误)相比,流不会造成麻烦,而且也不要试图存储海量数据 可能不是最好的解决方案,但确实很容易。 最后,您只需要合并结果即可。

在运行开始时定义:

num_cores = 8
file_sep = ","
outFiles = [open('out' + str(x) + ".csv", "a") for x in range(num_cores)]

然后在key_loop函数中:

def key_loop(key):
    test_df = pd.DataFrame(np.random.randn(1,4), columns=['a','b','c','d'])
    test_list = test_df.ix[0].tolist()
    outFiles[key % num_cores].write(file_sep.join([str(x) for x in test_list]) 
                                    + "\n")

之后,别忘了关闭: [x.close() for x in outFiles]

改进:

  • 遍历注释中提到的块。 一次写入/处理1行将比写入块慢得多。

  • 处理错误(关闭文件)

  • 重要说明:我不确定“ keys”变量的含义,但是那里的数字将不允许模以确保您将每个进程写入每个单独的流(12个键,模8将使2个进程写入相同的流文件)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM