如何在csv.DictReader中使用多进程?

时间:2019-02-12 08:27:58

标签: python python-3.x csv parallel-processing

这是一个用于计算直方图的脚本,我发现lib csv.py花费的时间最多。我如何并行运行它?

输入文件samtools.depth.gz的大小为14G,包含约30亿行。

SamplesList = ('Sample_A', 'Sample_B', 'Sample_C', 'Sample_D')
from collections import Counter
cDepthCnt = {key:Counter() for key in SamplesList}
cDepthStat = {key:[0,0] for key in SamplesList} # x and x^2

RecordCnt,MaxDepth = inStat('samtools.depth.gz')
print('xxx')

def inStat(inDepthFile):
    import gzip
    import csv
    RecordCnt = 0
    MaxDepth = 0
    with gzip.open(inDepthFile, 'rt') as tsvfin:
        tsvin = csv.DictReader(tsvfin, delimiter='\t', fieldnames=('ChrID','Pos')+SamplesList )
        RecordCnt += 1
        for row in tsvin:
            for k in SamplesList:
                theValue = int(row[k])
                if theValue > MaxDepth:
                    MaxDepth = theValue
                cDepthCnt[k][theValue] += 1
                cDepthStat[k][0] += theValue
                cDepthStat[k][1] += theValue * theValue
    return RecordCnt,MaxDepth

cProfile

有多种方法可以将大文件读取成块并将其与列表一起分发,例如https://stackoverflow.com/a/30294434/159695

bufsize = 65536
with open(path) as infile: 
    while True:
        lines = infile.readlines(bufsize)
        if not lines:
            break
        for line in lines:
            process(line)

但是,csv.DictReader仅接受文件句柄。

有一种方法可以在https://gist.github.com/jbylund/c37402573a896e5b5fc8处分割为临时文件,我想知道是否可以使用fifo即时进行分割。


我只是发现csv.DictReader接受任何支持迭代器协议的对象,并在每次调用其 next ()方法时都返回一个字符串-文件对象和列表对象均适用。 / p>

我已修改inStat()以接受行。您能帮我完成statPool()吗?

def statPool(inDepthFile):
    import gzip
    RecordCnt = 0
    MaxDepth = 0
    cDepthCnt = {key:Counter() for key in SamplesList}
    cDepthStat = {key:[0,0,0,0,0] for key in SamplesList} # x and x^2
    with gzip.open(inDepthFile, 'rt') as tsvfin:
        while True:
            lines = tsvfin.readlines(ChunkSize)
            if not lines:
                break
            with Pool(processes=4) as pool:
                res = pool.apply_async(inStat,[lines])
                iRecordCnt,iMaxDepth,icDepthCnt,icDepthStat = res.get()
            RecordCnt += iRecordCnt
            if iMaxDepth > MaxDepth:
                MaxDepth = iMaxDepth
            for k in SamplesList:
                cDepthCnt[k].update(icDepthCnt[k])
                cDepthStat[k][0] += icDepthStat[k][0]
                cDepthStat[k][1] += icDepthStat[k][1]
    return RecordCnt,MaxDepth,cDepthCnt,cDepthStat

我认为asyncio.Queue似乎是向多个csv.DictReader工作人员进行管道传送的好方法。

1 个答案:

答案 0 :(得分:0)

在全局范围内查找内容要比在本地范围内查找内容花费时间更长。

您要进行很多查找-我建议将代码更改为:

cDepthCnt = {key:Counter() for key in SamplesList}
cDepthStat = {key:[0,0] for key in SamplesList} # x and x^2

RecordCnt,MaxDepth = inStat('samtools.depth.gz', cDepthCnt, cDepthStat)
print('xxx')

def inStat(inDepthFile, depthCount, depthStat):
    # use the local depthCount, depthStat

加快部分速度。

一遍又一遍地访问相同的键时并行运行会在这些值上引入锁定,以避免发生意外-锁定/解锁也需要时间。您将不得不看看它是否更快。

您要做的就是对值求和-您可以对数据进行分区,并将4个部分用于4个(乘2)字典,然后将这4个字典加到全局字典中以避免锁定。