为什么多进程速度慢

0 投票
3 回答
3770 浏览
提问于 2025-04-18 10:50

我刚开始学习多进程的知识,目的是为了加快我的程序运行速度。于是,我写了两个简单的例子,从一堆随机数字中找出质数。

例子 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

所以,使用多进程让这个程序(可能是特定情况下)变得比不使用它要慢得多。有什么解释吗?我是不是用错了?

3 个回答

1

在多进程编程中,有一个简单的规则:如果把工作分开(创建子任务)和合并结果(把结果合在一起等)的时间,加起来比顺序执行的时间还要长,那么你的“并行”版本就会比顺序版本效率低。这就是你的情况。试着生成一百万个数字(把进程数量保持在10个),你就会看到差别。

@Sohcahtoa82 提供了一些很好的编码建议,记得参考一下。

1

你的 for i in range() 在调用 .join() 时,会等这个进程完成后才继续。所以,简单来说,你是启动了一个新进程来处理队列并报告结果,然后又启动了9个其他进程去检查一个空的队列。

.join()

这个方法会让调用它的线程一直等到被调用的进程结束,或者等到你设置的超时时间到。

使用进程池是一种更简单的方法来做同样的事情。你可以查看这个回答,了解如何用 map_async() 和工作进程池一起使用:

Python 多进程 map_async

3

我觉得你现在的多进程方法不太好。你不是把工作分成10个进程同时启动,而是一个一个地启动,每个进程只做一小部分工作,然后就结束了。这样的话,你的程序在运行过程中会创建(然后销毁)50个进程,这样会浪费很多资源。

而且,你在启动进程后立刻就把它们合并,这样的话其实就没有真正同时运行多个进程。合并操作会让主程序等着子进程完成后才能继续。

最后,返回结果的方式也可以更简单,不一定要用队列一个一个地取值。如果你能一次性启动每个进程,并给它们一组工作,然后把结果以列表的形式返回给主线程,这样可以减少使用队列带来的额外开销。

撰写回答