5

我正在做一个项目,我的代码吞吐量非常重要,经过一番考虑,我选择让我的程序线程化。

主线程和子线程都从两个共享字典中添加和删除。考虑到python中锁定的性能,我一直在浏览互联网上的一些输入,它是一个缓慢的操作等等。

所以我得到了什么,因为python实际上根本没有线程化(考虑到GIL只在一个核心上工作)如果我需要在我的应用程序中获得高性能,除了处理IO之外,我有什么可以通过使其线程化来赢得的?

编辑

实际问题是(在有见地的评论之后)

既然有 GIL,多线程在 python 中有意义吗?

4

2 回答 2

16

IMO,锁定解决方案对性能的影响很大,主要是在多线程真正等待它时。

获取和释放非竞争锁的成本应该是微不足道的。

这个线程显示了一个关于那个的测试。

好的,这是在 Linux 下使用 Python 3.2 获取和释放非竞争锁的成本:

$ python3 -m timeit \
  -s "from threading import Lock; l=Lock(); a=l.acquire; r=l.release" \
  "a(); r()"

10000000 loops, best of 3: 0.127 usec per loop

以下是调用虚拟 Python 函数的成本:

$ python3 -m timeit -s "def a(): pass" "a(); a()"

1000000 loops, best of 3: 0.221 usec per loop

这是调用一个普通的 C 函数(返回 False 单例)的成本:

$ python3 -m timeit -s "a=bool" "a(); a()"

10000000 loops, best of 3: 0.164 usec per loop

另外,请注意,使用锁作为上下文管理器实际上更慢,而不是你想象的更快:

$ python3 -m timeit -s "from threading import Lock; l=Lock()" \
  "with l: pass"

1000000 loops, best of 3: 0.242 usec per loop

至少在Linux下,锁性能似乎没有太大的提升空间,至少可以这么说。

PS:RLock 现在和 Lock 一样快:

$ python3 -m timeit \
  -s "from threading import RLock; l=RLock(); a=l.acquire; r=l.release" \
  "a(); r()"

10000000 loops, best of 3: 0.114 usec per loop
于 2015-05-08T03:17:27.777 回答
6

首先,任何语言的锁定都是性能瓶颈。尽可能减少锁定;例如,不要使用共享目录,而是创建一棵树,并让每个线程在该树的不同分支中工作。

由于您将执行大量 I/O,因此您的性能问题将存在,并且线程不一定会改善问题。首先研究事件驱动的架构:

GIL 在这里不太可能是您的问题;例如,只要线程进入 C 代码(几乎可以肯定在任何 I/O 调用期间),它就会被释放。如果它确实成为瓶颈,请转移到多个流程。例如,在我管理的一个大型 Intranet 集群上,我们运行 6 个进程,每 2 个线程,以充分利用所有 CPU 内核(其中 2 个进程负载非常轻)。

如果您觉得需要多个进程,请使用该multiprocessing模块或轻松启动服务器的多个实例(每个实例侦听不同的端口)并使用负载平衡器(如 haproxy)将流量引导到每个服务器。

于 2012-08-15T09:03:24.573 回答