Python线程速度出人意料地慢
我决定学习如何在Python中实现多线程,并做了一个比较,看看在双核CPU上可以获得什么样的性能提升。我发现我的简单多线程代码实际上比顺序代码运行得慢,我不明白为什么 我设计的测试是生成一个大的随机数列表,然后打印最大值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
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绑定操作。