【问题标题】:Multiprocessing and Multithreading多处理和多线程
【发布时间】:2012-03-17 05:29:58
【问题描述】:

我之前问过一个类似的问题,但没有得到有用的回答,所以我会尽量让事情更清楚。

我正在寻找的是对某个 linux 命令运行多线程或最好是多处理方法。如果有人熟悉Picard,我想在 bam 文件上运行早期版本,同时在同一个 bam 文件上运行较新版本。这个想法是测试新版本的速度有多快,以及它是否给出相同的结果。

我的主要问题是我不知道如何在 Popen 命令上实现多处理。例如

cmd1 = ['nice', 'time', 'java', '-Xmx6G', '-jar', '/comparison/old_picard/MarkDuplicates.jar', 'I=/comparison/old.bam', 'O=/comparison/old_picard/markdups/old.dupsFlagged.bam', 'M=/comparison/old_picard/markdups/old.metrics.txt', 'TMP_DIR=/comparison', 'VALIDATION_STRINGENCY=LENIENT', 'ASSUME_SORTED=true']
cmd2 = ['nice', 'time', 'java', '-Xmx6G', '-jar', '/comparison/new_picard/MarkDuplicates.jar', 'I=/comparison/new.bam', 'O=/comparison/new_picard/markdups/new.dupsFlagged.bam', 'M=/comparison/new_picard/markdups/new.metrics.txt', 'TMP_DIR=/comparison', 'VALIDATION_STRINGENCY=LENIENT', 'ASSUME_SORTED=true']

c1 = subprocess.Popen(cmd1, stdout=subprocess.PIPE)
c2 = subprocess.Popen(cmd2, stdout=subprocess.PIPE)

然后我有一个定时器功能:

def timeit(c):
    past = time.time()
    results = [c.communicate()]
    present = time.time()
    total = present - past
    results.append(total)
    return results

我想做的是:

p = Process(target=timeit, args=(c1,c2))
p.start()
p.join()

但是我得到“Popen object not iterable”错误。有没有人比我现在有更好的主意?我不想朝着完全不同的方向前进,只是为了撞到另一堵墙。总之,我想同时在一个 cpu 上运行 c1 并在另一个 cpu 上运行 c2,请帮助!

【问题讨论】:

  • 为什么要同时运行它们?我怀疑你会从中得到有意义的结果。
  • 您是否考虑过按顺序运行它们,这样您就可以真正模仿该过程本身? CPU 不是唯一的共享资源,因此如果这是一项内存密集型或磁盘密集型操作,您可能有一个进程或线程胜出,并且看起来更快。

标签: python multithreading subprocess multiprocessing


【解决方案1】:

我认为这样的事情应该可行:

p1 = Process(target=timeit, args=(c1,))
p2 = Process(target=timeit, args=(c2,))
p1.start()
p2.start()
p1.join()
p2.join()

我不知道你的迭代错误在哪里(它是哪一行?)。

另外,我认为你最好分开运行它们。当你一起运行它们时,你会冒一个进程被赋予更多 CPU 时间并且看起来更快的风险,即使它不是。

【讨论】:

    【解决方案2】:

    而不是传递 subprocess.Popen(当它第一次定义时,它将串行而不是并行运行它们),传递 命令:

    import time
    import subprocess
    from multiprocessing import Process
    
    cmd1 = ['nice', 'time', 'java', '-Xmx6G', '-jar', '/comparison/old_picard/MarkDuplicates.jar', 'I=/comparison/old.bam', 'O=/comparison/old_picard/markdups/old.dupsFlagged.bam', 'M=/comparison/old_picard/markdups/old.metrics.txt', 'TMP_DIR=/comparison', 'VALIDATION_STRINGENCY=LENIENT', 'ASSUME_SORTED=true']
    cmd2 = ['nice', 'time', 'java', '-Xmx6G', '-jar', '/comparison/new_picard/MarkDuplicates.jar', 'I=/comparison/new.bam', 'O=/comparison/new_picard/markdups/new.dupsFlagged.bam', 'M=/comparison/new_picard/markdups/new.metrics.txt', 'TMP_DIR=/comparison', 'VALIDATION_STRINGENCY=LENIENT', 'ASSUME_SORTED=true']
    
    def timeit(cmd):
        print cmd
        past = time.time()
        p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
        results = [p.communicate()]
        present = time.time()
        total = present - past
        results.append(total)
        return results
    
    p1 = Process(target=timeit, args=(cmd1,))
    p2 = Process(target=timeit, args=(cmd2,))
    
    for p in (p1, p2):
        p.start()
    for p in (p1, p2):
        p.join()
    

    ETA:虽然上述解决方案通常是进行多处理的方法,但@Jordan 是完全正确的,您不应该使用这种方法对两个版本的软件进行计时。为什么不按顺序运行它们?

    【讨论】:

    • 这些任务可能需要很长时间才能运行,因此我将使用具有更大功率的共享主机来运行它们。如果我按顺序运行它们(先说旧版本)并且机器处理器负载很低,然后在几个小时后运行新版本的 picard 但更多用户向主机添加了任务导致它进入高负载.然后第二个任务会因为其他流量而运行得更慢。因此,没有必要为它们计时,因为统计数据不会处于相同的条件下。
    • 还有你为什么没有把 p.join() 和 p.start() 放在同一个 for 循环中?
    • 哈哈谢谢。我没有将p.join() 放在同一个循环中,因为那样它就不会并行。 p.join() 表示“等待进程 p 完成”。如果它们在同一个循环中,它将启动一个进程,等待它完成,启动另一个进程,然后等待它完成(因此,根本没有并行化)
    • 啊,是的,我刚刚读到这个。 python 文档有时难以解释。我还有一件事要问。这就是我如何巧妙地呈现我的结果?比如我想在之后打印每个函数的时间?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-08
    • 1970-01-01
    • 1970-01-01
    • 2011-09-17
    • 2013-04-03
    相关资源
    最近更新 更多