Python:为何线程函数比非线程慢

5 投票
2 回答
2303 浏览
提问于 2025-04-18 04:36

你好,我正在尝试计算前10000个质数。

我先是用单线程的方式计算,然后再把计算分成1到5000和5001到10000两部分。我原本以为使用多线程会让速度明显变快,但结果却是这样的:

    --------Results--------
Non threaded Duration:  0.012244000000000005 seconds
Threaded Duration:  0.012839000000000017 seconds

实际上,没什么太大的区别,反而是多线程的函数稍微慢了一点。

这是怎么回事呢?

这是我的代码:

import math
from threading import Thread

def nonThreaded():
    primeNtoM(1,10000)


def threaded():
    t1 = Thread(target=primeNtoM, args=(1,5000))
    t2 = Thread(target=primeNtoM, args=(5001,10000))
    t1.start()
    t2.start()
    t1.join()
    t2.join()


def is_prime(n):
    if n % 2 == 0 and n > 2: 
        return False
    for i in range(3, int(math.sqrt(n)) + 1, 2):
        if n % i == 0:
            return False
    return True

def primeNtoM(n,m):
    L = list()
    if (n > m):
        print("n should be smaller than m")
        return
    for i in range(n,m):
        if(is_prime(i)):
                L.append(i)

if __name__ == '__main__':
    import time
    print("--------Nonthreaded calculation--------")
    nTstart_time = time.clock()
    nonThreaded()
    nonThreadedTime = time.clock() - nTstart_time

    print("--------Threaded calculation--------")

    Tstart_time = time.clock()
    threaded()
    threadedTime = time.clock() - Tstart_time

    print("--------Results--------")
    print ("Non threaded Duration: ",nonThreadedTime, "seconds")
    print ("Threaded Duration: ",threadedTime, "seconds")

2 个回答

4

你可以使用 multiprocessing 模块,它的效果如下:

('Non threaded Duration: ', 0.016599999999999997, 'seconds')
('Threaded Duration: ', 0.007172000000000005, 'seconds')

...只需对你的代码做这些小改动(把'Thread'改成'Process'):

import math
#from threading import Thread
from multiprocessing import Process

def nonThreaded():
    primeNtoM(1,10000)


def threaded():
    #t1 = Thread(target=primeNtoM, args=(1,5000))
    #t2 = Thread(target=primeNtoM, args=(5001,10000))
    t1 = Process(target=primeNtoM, args=(1,5000))
    t2 = Process(target=primeNtoM, args=(5001,10000))
    t1.start()
    t2.start()
    t1.join()
    t2.join()

通过创建真正的操作系统进程,而不是使用线程,你就能解决@Luis Masuelli提到的GIL问题。

multiprocessing 是一个支持创建进程的工具包,它的使用方式和线程模块类似。这个包可以在本地和远程同时运行,从而有效地绕过了全局解释器锁(GIL),因为它使用的是子进程而不是线程。这样,multiprocessing 模块就能让程序员充分利用机器上的多个处理器。它可以在Unix和Windows系统上运行。

12

来源: https://wiki.python.org/moin/GlobalInterpreterLock

在CPython中,全局解释器锁(GIL)是一种互斥锁,它阻止多个本地线程同时执行Python字节码。这个锁的存在主要是因为CPython的内存管理不是线程安全的。(不过,由于GIL的存在,其他一些功能也开始依赖于它提供的保证。)

这意味着:因为Python在处理CPU密集型任务时不是线程安全的,所以它不允许在同一个进程中同时运行多个字节码。因此,你的线程会交替执行,而这种切换的开销就是你额外花费的时间。

撰写回答