Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/349.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何用python(FASTA的GC计算器)并行化这段代码?_Python_Python Multiprocessing_Dna Sequence - Fatal编程技术网

如何用python(FASTA的GC计算器)并行化这段代码?

如何用python(FASTA的GC计算器)并行化这段代码?,python,python-multiprocessing,dna-sequence,Python,Python Multiprocessing,Dna Sequence,说到编程,我是个新手。我已经读完了《面向生物学家的实用计算》一书,现在正在研究一些稍微高级一些的概念 我编写了一个Python(2.7)脚本,它读取.fasta文件并计算GC内容。代码如下所示 我正在处理的文件很麻烦(~3.9GB),我想知道是否有一种方法可以利用多个处理器,或者是否值得花点时间。我有一个四核(超线程)英特尔I-7 2600K处理器 我运行了代码并查看了系统资源(附图片),以查看CPU上的负载。这个进程CPU有限吗?是IO有限公司吗?这些概念对我来说是很新的。我使用了多处理模块和

说到编程,我是个新手。我已经读完了《面向生物学家的实用计算》一书,现在正在研究一些稍微高级一些的概念

我编写了一个Python(2.7)脚本,它读取.fasta文件并计算GC内容。代码如下所示

我正在处理的文件很麻烦(~3.9GB),我想知道是否有一种方法可以利用多个处理器,或者是否值得花点时间。我有一个四核(超线程)英特尔I-7 2600K处理器

我运行了代码并查看了系统资源(附图片),以查看CPU上的负载。这个进程CPU有限吗?是IO有限公司吗?这些概念对我来说是很新的。我使用了多处理模块和Pool(),但没有用(可能是因为我的函数返回了一个元组)

代码如下:

def GC_calc(InFile):
    Iteration = 0
    GC = 0
    Total = 0
    for Line in InFile:
        if Line[0] != ">":
            GC = GC + Line.count('G') + Line.count('C')
            Total = Total + len(Line)
            Iteration = Iteration + 1
            print Iteration
    GCC = 100 * GC / Total
    return (GC, Total, GCC)


InFileName = "WS_Genome_v1.fasta"
InFile = open(InFileName, 'r')
results = GC_calc(InFile)
print results

目前,代码的主要瓶颈是
打印迭代
。打印到标准输出非常慢。如果您删除这一行,或者至少,如果您确实需要它,请将它移到另一个线程,我希望性能会有很大的提升。然而,线程管理是一个高级主题,我建议现在不要讨论它

另一个可能的瓶颈是从文件中读取数据。文件IO可能很慢,尤其是当您的机器上只有一个HDD时。对于单个HDD,您根本不需要使用多处理,因为您无法为处理器核心提供足够的数据。面向性能的RAID和SSD在这方面可以有所帮助

最后一点是尝试使用
grep
和类似的文本操作程序来代替python。他们经过了几十年的优化,有很好的机会更快地工作。在这方面有很多问题,
grep
优于python。或者,在将数据传递给脚本之前,至少可以使用FASTA头:

$ grep "^[>]" WS_Genome_v1.fasta | python gc_calc.py

(取自
grep“^[>]”
)在这种情况下,您不应该打开脚本中的文件,而是应该从
sys.stdin
中读取行,就像您现在这样做一样。

基本上,您在计算每行中的
C
G
的数量,并计算行的长度。 只有在最后你才能计算出总数

这样的过程很容易并行进行,因为每条线的计算是独立的

假设计算是在CPython(来自python.org的)中完成的,
threading
不会因为GIL而大大提高性能

这些计算可以与
多处理.Pool
并行进行。 进程不像线程那样共享数据。我们不想将3.9GB文件的一部分发送到每个工作进程! 因此,您希望每个辅助进程自己打开文件。操作系统的缓存应该注意同一文件中的页面不会多次加载到内存中

如果您有N个核,我将创建worker函数,以便处理每个第N行,并带有偏移量

def worker(arguments):
    n = os.cpu_count() + 1
    infile, offset = arguments
    with open(infile) as f:
        cg = 0
        totlen = 0
        count = 1
        for line in f:
            if (count % n) - offset == 0:
                if not line.startswith('>'):
                    cg += line.count('C') +
                          line.count('G')
                    totlen += len(line)
            count += 1
    return (cg, totlen)
你可以这样管理游泳池

import multiprocessing as mp
from os import cpu_count

pool = mp.Pool()
results = pool.map(worker, [('infile', n) for n in range(1, cpu_count()+1)])
默认情况下,
创建的工人数量与CPU的核心数量相同

results
将是一个(cg,len)元组列表,您可以轻松地求和


编辑:更新以修复模零错误。

我现在有了一个用于并行化的工作代码(特别感谢@Roland Smith)。我只需要对代码做两个小的修改,还有一个关于.fasta文件的结构的警告。最终(工作)代码如下:

###ONLY WORKS WHEN THERE ARE NO BREAKS IN SEQUENCE LINES###

def GC_calc(arguments):
    n = mp.cpu_count()
    InFile, offset = arguments
    with open(InFile) as f:
        GC    = 0
        Total = 0
        count = 0
        for Line in f:
            if (count % n) - offset == 0:
                if Line[0] != ">":
                    Line = Line.strip('\n')
                    GC += Line.count('G') + Line.count('C')
                    Total += len(Line)
            count += 1
    return (GC, Total)

import time
import multiprocessing as mp

startTime = time.time()
pool = mp.Pool()
results = pool.map(GC_calc, [('WS_Genome_v2.fasta', n) for n in range(1, mp.cpu_count()+1)])
endTime = time.time()
workTime = endTime - startTime
#Takes the tuples, parses them out, adds them
GC_List = []
Tot_List = []
# x = GC count, y = total count: results = [(x,y), (x,y), (x,y),...(x,y)]
for x,y in results:
    GC_List.append(x)
    Tot_List.append(y)

GC_Final = sum(GC_List)
Tot_Final = sum(Tot_List)

GCC = 100*float(GC_Final)/float(Tot_Final)

print results
print
print "Number GC = ", GC_Final
print "Total bp = ", Tot_Final
print "GC Content = %.3f%%" % (GCC)
print
endTime = time.time()
workTime = endTime - startTime
print "The job took %.5f seconds to complete" % (workTime)
需要注意的是.fasta文件本身在序列中不能有中断。我的原始代码并没有问题,但当序列被分成多行时,这段代码将无法正常工作。这非常简单,可以通过命令行进行修复

我还必须在两个地方修改代码:

n=mp.cpu\u计数()

计数=0

最初,count设置为1,n设置为mp.cpu_count()+1。这导致计数不准确,即使在文件更正之后也是如此。缺点是它还允许所有8个内核(好吧,线程)工作。新代码只允许4在任何给定时间工作


但是它确实把这个过程从23秒加速到了13秒!因此,我认为这是一次成功(除了更正原始.fasta文件所需的时间)。

如果您正在读取同一文件,多处理将不会对您有所帮助,因为您几乎肯定会受到硬盘读取速度的限制。另外,请关闭您的文件。。。python的
with
关键字非常有助于确保文件在处理完毕后关闭。但是,如果您希望获得多处理方面的帮助只是为了学习,您必须发布实际涉及并行处理的代码,以便我们能够帮助您。如果您实际上没有任何错误,您可能会在@Aaron上找到更多的运气啊,是的,原始代码确实有一个close命令-忘了这里!非常感谢。我可能会尝试使用pool()函数生成一些代码(重新创建它),但当我尝试使用pool.map将函数拆分为4个进程时,确实收到了一条错误消息。问题在于我如何尝试分割输入(它不喜欢我使用pool.map函数和我的函数,并尝试分割我的_文件/4)。我在遵循一个生成随机数据的示例,然后以这种方式分割这些数据(如上),所以我的方法显然不合适。这非常有趣!我将尝试一下并比较性能。我确实使用grep提取了文件的另一个版本(删除了“>”行和重复序列),但没有想到将其直接传输到脚本。打印语句可以让我跟踪进度和速度,而无需完成整个过程,但我可以看到这可能会减慢速度@坎菲斯-这个q