【问题标题】:Python threading unexpectedly slowerPython 线程意外地变慢了
【发布时间】:2010-06-25 20:07:15
【问题描述】:

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

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

from random import random
import threading

def ox():
    print max([random() for x in xrange(20000000)])

ox() 在我的 Intel Core 2 Duo 上完成大约需要 6 秒,而 ox();ox() 大约需要 12 秒。

然后我尝试从两个线程调用 ox() 以查看完成的速度。

def go():
    r = threading.Thread(target=ox)
    r.start()
    ox()

go() 大约需要 18 秒才能完成,两个结果在 1 秒内打印。为什么要慢一点?

我怀疑 ox() 正在自动并行化,因为如果查看 Windows 任务管理器性能选项卡,并在我的 python 控制台中调用 ox(),两个处理器的利用率都会跳到大约 75% 直到它完成。 Python 会在可能的情况下自动并行化 max() 之类的东西吗?

【问题讨论】:

    标签: python multithreading parallel-processing


    【解决方案1】:
    1. Python 有 GIL。 Python 字节码一次只能由一个处理器执行。只有某些 C 模块(不管理 Python 状态)才能同时运行。
    2. Python GIL 在锁定线程之间的状态时会产生巨大的开销。在较新的版本或开发分支中对此进行了修复 - 至少应该使多线程 CPU 绑定代码与单线程代码一样快。

    您需要使用多进程框架与 Python 进行并行化。幸运的是,Python 附带的 multiprocessing 模块使这变得相当容易。

    很少有语言可以自动并行化表达式。如果这是你想要的功能,我建议 Haskell (Data Parallel Haskell)

    【讨论】:

    • 值得注意的是,线程在 Python 中对于某些类型的任务仍然有用,例如 I/O 绑定操作。
    【解决方案2】:

    问题出在函数 random() 如果您从代码中删除随机数。 两个内核都尝试访问随机函数的共享状态。 核心相应地工作,并在缓存同步上花费了大量时间。 这种行为被称为虚假分享。 阅读这篇文章False Sharing

    【讨论】:

      【解决方案3】:

      正如 Yann 正确指出的那样,Python GIL 阻止了在此示例中发生并行化。您可以使用 python 多处理模块来解决这个问题,或者如果您愿意使用其他开源库,Ray 也是解决 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 的两次调用加起来需要 1.87 秒,因此我们在这里获得了几乎完美的并行化。

      Ray 还可以非常高效地在任务之间共享数据,在一台机器上它会在后台使用共享内存,请参阅 https://ray-project.github.io/2017/10/15/fast-python-serialization-with-ray-and-arrow.html

      您还可以在集群或云上的不同机器上运行相同的程序,而无需修改程序,请参阅文档(https://ray.readthedocs.io/en/latest/using-ray-on-a-cluster.htmlhttps://ray.readthedocs.io/en/latest/autoscaling.html)。

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

      【讨论】:

        猜你喜欢
        • 2021-12-24
        • 1970-01-01
        • 2014-03-09
        • 1970-01-01
        • 2021-04-02
        • 1970-01-01
        • 1970-01-01
        • 2013-10-15
        • 2020-02-18
        相关资源
        最近更新 更多