使用python多处理运行具有不同参数组合的循环的脚本

时间:2017-05-01 11:26:15

标签: python python-2.7 multiprocessing

我很抱歉,如果这是另一个问题的副本,但我已经读过其他试图使用多处理的威胁,我不得不说这只会让我更加困惑(我是一名生物学家,试图处理很多问题)服务器中的数据和文件,我不熟悉正确的语言。我的不好!)。

我基本上想要的是同时在脚本中运行一次循环5次,这样我就可以利用服务器中有多个CPU的事实。如果我没有不同的参数组合作为此脚本的输入,这将很简单。该脚本循环遍历我的文件夹中的文件(我的实验中的不同示例),根据这些文件的名称创建输出名称,并修改我提交给os.system以运行程序的字符串。在我的程序调用中,我还需要为每个示例指定一个不同的引用文件,我通过在脚本中构建一个字典来实现。

我这样称呼我的剧本:

run_ProgramXPTO.py list.txt

在list.txt中我有这样的东西,它指定了每个样本文件的参考文件的路径。假设我有5个样本,所以我会:

sampleA /path/to/reference/lion.reference
sampleB /path/to/reference/cat.reference
sampleC /path/to/reference/tiger.reference
sampleD /path/to/reference/cow.reference
sampleE /path/to/reference/dog.reference

然后,在此脚本中,我为示例名称添加必要的扩展,创建输出名称并设置带有引用路径的参数。我对这个计划的要求是:

do_this_for_me -input sampleA_call.vcf.gz -reference /path/to/reference/lion.reference -output sampleA_call.stats

我试图使用多处理使这个循环同时运行5次,但是发生的事情是相同的输入文件运行5次,而不是使用不同的输入文件运行5次的程序。所以,我做错了什么,不明白如何使用多处理来搜索网页......

所以,这就是我目前在run_ProgramXPTO.py中的内容:

import sys
import os
import glob
import multiprocessing

#this reads a file with paths to references
list=sys.argv[1]

#this makes a dictionary from the input file where for each sample
#I now have a path to another file (reference) in my system
def make_PathDir(list):
    list=open(list,"r")
    mydir={}

    for line in list:
        row=line.strip().split('\t')
        key=row[0]
        value=row[1]
        mydir.setdefault(key,value)

    return mydir

#call the program specifying, for each input, an output name
#and the path to reference file 

def worker(x):

    for i in x:
        name1=i.strip("./")
        name2=name1.strip("_call.vcf.gz")
        output=str(name2+"_call.stats")

        path=PathDir.get(name2)

        command="bcftools stats -F %s -s - %s > %s" % (path, name1, output)

        os.system(command)

    return

PathDir=make_PathDir(list)


#and here, run my program 5 times for each input file
if __name__ == '__main__':
    jobs = []
    for i in range(5):
        f=glob.glob("./*_call.vcf.gz")
        p = multiprocessing.Process(target=worker,args=[f])
        jobs.append(p)
        p.start()

非常感谢提前。

1 个答案:

答案 0 :(得分:1)

Python 3.2+解决方案(我错过了Python 2.7标签)。如果它必须是Python 2,我们可以修改它。在此期间,这应该会给你一个想法。它用更简单,更Pythonic的方式替换你的一些代码。

#!/usr/bin/env python3

import sys
import os
import glob
import argparse
import functools
import concurrent.futures
from concurrent.futures import ThreadPoolExecutor as PoolExecutor


NUM_CONCURRENT_WORKERS = 5


def process_sample(sample_to_reference_map, input_filename):
    """Run bcftools stats on input_filename using the correct reference file"""

    sample_basename = input_filename.rstrip('_call.vcf.gz')
    output_filename = '{}_call.stats'.format(sample_basename)
    reference_filename = sample_to_reference_map[sample_basename]
    command = 'bcftools stats -F {} -s - {} > {}'.format(
        reference_filename,
        input_filename,
        output_filename)
    os.system(command)


def process_args():
    parser = argparse.ArgumentParser(prog=sys.argv[0])
    parser.add_argument('sample_map')
    return parser.parse_args()


def main():
    args = process_args()

    # Read sample to reference mapping
    with open(args.sample_map) as f:
        sample_to_reference_map = dict(line.strip().split() for line in f)

    # Create a worker function that has the map passed to it
    worker = functools.partial(process_sample, sample_to_reference_map)

    # Use a pool of workers to process samples
    with PoolExecutor(max_workers=NUM_CONCURRENT_WORKERS) as executor:
        # Get a list of sample files to process
        input_files = glob.glob('*_call.vcf.gz')
        # Queue a background job for each file, and keep a job-to-sample
        # map for status
        future_to_sample = {executor.submit(worker, f): f for f in input_files}
        # Print messages for each as they finish
        for future in concurrent.futures.as_completed(future_to_sample):
            print('{} completed'.format(future_to_sample[future]))


if __name__ == '__main__':
    main()