Python线程速度出人意料地慢

Python线程速度出人意料地慢,python,multithreading,parallel-processing,Python,Multithreading,Parallel Processing,我决定学习如何在Python中实现多线程,并做了一个比较,看看在双核CPU上可以获得什么样的性能提升。我发现我的简单多线程代码实际上比顺序代码运行得慢,我不明白为什么 我设计的测试是生成一个大的随机数列表,然后打印最大值 from random import random import threading def ox(): print max([random() for x in xrange(20000000)]) ox();ox()大约需要12秒 然后,我尝试从两个线程调用ox

我决定学习如何在Python中实现多线程,并做了一个比较,看看在双核CPU上可以获得什么样的性能提升。我发现我的简单多线程代码实际上比顺序代码运行得慢,我不明白为什么

我设计的测试是生成一个大的随机数列表,然后打印最大值

from random import random
import threading

def ox():
    print max([random() for x in xrange(20000000)])
ox();ox()
大约需要12秒

然后,我尝试从两个线程调用ox(),看看完成的速度有多快

def go():
    r = threading.Thread(target=ox)
    r.start()
    ox()
go()。为什么要慢一点

我怀疑
ox()。Python会自动并行化类似于
max()
的东西吗

  • Python拥有GIL。Python字节码一次只能由单个处理器执行。只有某些C模块(不管理Python状态)能够并发运行
  • Python GIL在锁定线程之间的状态方面有巨大的开销。在较新的版本或开发分支中有针对这一问题的修复程序,至少应该使多线程CPU绑定代码与单线程代码一样快
  • 您需要使用多进程框架来与Python并行。幸运的是,Python附带的模块使这变得相当容易


    很少有语言能够自动并行化表达式。如果这是您想要的功能,我建议使用Haskell(数据并行Haskell)

    问题在于函数random() 如果从代码中删除随机项。 两个内核都试图访问随机函数的共享状态。 内核必然会工作,并在缓存同步上花费大量时间。 这种行为被称为虚假分享。
    阅读本文

    正如Yann正确指出的那样,Python GIL阻止了本例中的并行化。您可以使用python多处理模块来解决这个问题,或者如果您愿意使用其他开源库,这也是解决GIL问题的一个很好的选择,并且比python多处理库更易于使用,并且具有更多的功能

    以下是如何使用Ray并行化代码示例:

    from random import random
    import ray
    
    ray.init()
    
    @ray.remote
    def ox():
        print(max([random() for x in range(20000000)]))
    
    %time x = ox.remote(); y = ox.remote(); ray.get([x, y])
    
    在我的机器上,您发布的单线程ox()代码需要1.84秒,两个调用加上ray take 1.87秒,因此我们在这里得到了几乎完美的并行化

    Ray还使任务之间的数据共享变得非常高效,在一台机器上,它将使用引擎盖下的共享内存,请参阅

    您还可以在集群或云上的不同机器上运行相同的程序,而无需修改程序,请参阅文档(和)


    免责声明:我是Ray开发人员之一。

    值得注意的是,线程在Python中对于某些类型的任务仍然很有用,例如I/O绑定操作。