[英]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
同样,这里的变化是
resultset
,而不是不必要地首先将其复制到列表中。 keys
列表直接输入pool.imap
而不是根据它创建生成器理解。 chunksize
到imap
比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.