【问题标题】:Python: Why is threaded function slower than non threadPython:为什么线程函数比非线程慢
【发布时间】:2014-04-28 15:22:35
【问题描述】:

您好,我正在尝试计算前 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")

【问题讨论】:

    标签: python multithreading


    【解决方案1】:

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

    在 CPython 中,全局解释器锁或 GIL 是一个互斥锁,可防止多个本机线程同时执行 Python 字节码。这个锁是必要的,主要是因为 CPython 的内存管理不是线程安全的。 (但是,由于 GIL 的存在,其他功能已经发展到依赖于它强制执行的保证。)

    这意味着:由于这是 CPU 密集型的,而且 python 不是线程安全的,它不允许您在同一个进程中同时运行多个字节码。因此,您的线程会相互交替,而切换开销就是您获得的额外时间。

    【讨论】:

    • 你的回答比我的好很多,所以我删了:)
    • 老实说我不知道​​,但我读到有一个multiprocessing 模块。它产生分叉,在 unix 环境中,进程分叉比线程分叉慢一点(上下文切换更快更轻)。然而这在 Windows 中又是一个问题
    【解决方案2】:

    您可以使用multiprocessing 模块,其结果如下:

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

    ...在对您的代码进行这些更改之后(将“线程”更改为“进程”):

    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 是一个支持使用 API 类似于 threading 模块。多处理包 提供本地和远程并发,有效地回避 通过使用子进程而不是线程来全局解释器锁。 因此,多处理模块允许程序员完全 利用给定机器上的多个处理器。它在两个 Unix 上运行 和窗户。

    【讨论】:

    • 但是我是在创建一个新进程而不是线程还是我错了?
    • 完全正确——通过创建多个进程,您可以例如在多个内核上运行您的代码,不受全局解释器锁的影响。
    • 请记住,在 unix 环境中,在进程之间进行上下文切换并不比在同一进程中进行线程切换困难得多。 PCB 在 unix 中是轻量级的(但在 windows 中不是,所以它在 windows 中又是一个问题)
    • 好的,但事实上这不是我试图实现的解决方案。那么哪种代码适合线程呢?
    • @AzzUrr1 您根本无法在 Python 中使用线程获得令人满意的解决方案。您必须使用多个进程。
    猜你喜欢
    • 2014-07-21
    • 2015-07-09
    • 2016-10-29
    • 1970-01-01
    • 1970-01-01
    • 2021-03-27
    • 1970-01-01
    • 2015-08-22
    • 2019-02-20
    相关资源
    最近更新 更多