【问题标题】:Why multiprocessing is slow为什么多处理很慢
【发布时间】:2014-08-14 02:46:04
【问题描述】:

为了加快我的程序,我刚开始阅读有关多处理的文章。 因此,我编写了两个基本示例来从随机数列表中提取素数。

示例 1:使用多处理

from multiprocessing import Process, Queue
from random import randrange
import time

def randomList(q, size, nmax):
    l = []
    r = randrange(2, nmax)
    for i in range(size):
        while r in l: # avoid replicating numbers
            r = randrange(2, nmax)
        l.append(r)
        q.put(r)

def checkPrime(numbers, prime):
    if numbers.qsize():
        n = numbers.get()
        count = 0 # divisors counter
        d = 2 # divisor
        while not count and d<=n/2:
            if n%d:
                d+=1
            else:
                count+=1
        if not count:
            prime.put(n)

if __name__=="__main__":
    numbers = Queue()
    prime = Queue()
    randomList(numbers, 50, 1000) # 50 number | 100 max value
    t1 = time.time()
    while numbers.qsize():
        for i in range(10): # Running 10 processes 
            p=Process(target=checkPrime, args=(numbers, prime))
            p.start()
            p.join()
    t2 = time.time()
    primes = []
    for i in range(prime.qsize()):
        primes.append(prime.get())
    print("[+] Prime numbers:")
    print(primes)
    print("[+] Time elapsed:"+str(t2-t1))

输出:

[+] Prime numbers:
[17, 227, 389, 593, 953, 757]
[+] Time elapsed:9.41699981689

示例 2:与示例 1 相同,但没有多处理

[...]
    while numbers.qsize():
        checkPrime(numbers, prime)
[...]

输出:

[+] Prime numbers:
[193, 227, 241, 439, 499, 877, 479, 743, 929]
[+] Time elapsed:0.00999999046326

因此,多处理使这个程序(特别是可能)比不使用它时要慢得多。 有什么解释吗?我用错了吗?

【问题讨论】:

  • 无法复制您的问题。多处理返回Time elapsed:0.311047077179
  • 与多处理的开销相比,您的操作太便宜了?

标签: python performance python-2.7 multiprocessing primes


【解决方案1】:

多处理中有一个简单的规则:如果用于创建多处理的拆分(创建子任务)+ 加入(连接结果等)的工作 > 顺序时间,那么您的“并行”版本相对于顺序版本将是低效的.这是你的情况。尝试生成一百万个数字(将您的进程数保持在 10 以内),您会看到差异。

@Sohcahtoa82 提供的良好编码技巧。也要记住它们。

【讨论】:

    【解决方案2】:

    当您 .join() 时,您的 for i in range() 正在等待该过程完成。因此,基本上,您正在生成一个新进程,该进程消耗队列并报告结果,然后生成 9 个其他进程来检查空队列。

    .join()

    阻塞调用线程,直到调用 join() 方法的进程终止或直到发生可选超时。

    池是做同样事情的一种更简单的方法。 检查此答案以将map_async() 与一组工人一起使用:

    Python Multiprocessing map_async

    【讨论】:

    • 我尝试使用 10 个工作人员池,使用“apply”方法时程序需要 6.3 秒,使用“apply_async”时需要 1.6 秒。还是很慢
    • 正如 Fabricator 所提到的,数据量可能并不显着,无法看到可以验证启动其他进程的开销的收益。您可以尝试将样本量增加 100 倍左右。
    • 我使用randomList(numbers, 15000, 150000)得到了 5s(多进程)vs 9s(单进程)
    【解决方案3】:

    我认为您的多处理方法很差。不是将工作分成 10 个进程并同时启动它们,而是一次启动一个进程,每个进程都在做一个工作单元然后退出。您的实现将在其生命周期内创建(然后销毁)50 个进程,这会产生大量开销。

    您还可以在启动进程后立即加入这些进程,这样您就不会真正运行多个进程。加入让它等待子进程完成后再继续。

    最后,必须有一种更好的方法来返回结果,即使用队列并一次获取一个值。如果您可以一次启动每个进程并完成一组工作,然后将列表中的结果返回给主线程,则可以减少使用队列的开销。

    【讨论】:

    • 1) 在问这个问题之前,我尝试在启动它们后加入这 10 个进程,这让事情变得更糟,它变得内存和 CPU 密集,计算机死机,我不得不重新启动它。 2)在处理多处理和多线程时应该使用队列,因为它是进程和线程安全的。
    • 当然,启动/加入 10 个进程将是 CPU 密集型的(除非您有超过 10 个 CPU 内核)。你给它同时做 10 件事。这就是多处理的意义所在。您当前的实现实际上是 NOT 进行任何多处理,但受到多处理所涉及的每一点开销的影响。队列对于多处理很有用,因为它们是过程安全的,当然,但是每次与队列之间的传输都会产生开销。如果可能,您应该尽量减少传输次数并最大化每次传输的大小。
    • 我理解你的代码就好了。您正在生成 2 到 1000 之间的 50 个随机数并将它们全部放入队列中,然后试图找出其中哪些是素数,并且您正在尝试通过多处理来加速它,但是您的代码完全是错误的并且是不是书面的多处理。您将在启动后立即加入新进程,这将阻止更多进程在新进程完成之前产生,从而有效地阻止您进行实际的多处理。此外,一旦找到除数,您检查素数的方法就应该退出
    • 显然,您不了解我的代码的多处理部分。你不需要在下一条评论中写解释,因为我已经知道它是如何工作的。另外,我确实提到了为什么我必须在启动后加入这个过程......
    猜你喜欢
    • 2015-01-16
    • 1970-01-01
    • 2013-10-05
    • 2012-06-01
    • 2018-06-11
    • 1970-01-01
    • 1970-01-01
    • 2019-10-02
    相关资源
    最近更新 更多