线程如何在Python中工作,以及常见的Python线程特定缺陷是什么?
我一直试图围绕Python的线程工作,很难find有关它们如何操作的良好信息。 我可能只是错过了一个链接或东西,但似乎官方文件是不是很透彻的主题,我一直没能find一个很好的文字。
据我所知,一次只能运行一个线程,并且每10个指令左右切换一次活动线程?
哪里有一个很好的解释,或者你能提供一个吗? 在Python中使用线程时遇到的常见问题也是非常好的。
是的,由于全局解释器锁(GIL),一次只能运行一个线程。 这里有一些关于这方面的见解的链接:
- http://www.artima.com/weblogs/viewpost.jsp?thread=214235
- http://smoothspan.wordpress.com/2007/09/14/guido-is-right-to-leave-the-gil-in-python-not-for-multicore-but-for-utility-computing/
从最后一个链接一个有趣的报价:
让我解释一下这一切的意思。 线程在相同的虚拟机内运行,因此可以在同一台物理机器上运行。 进程可以在同一台物理机器上或另一台物理机器上运行。 如果你围绕线程构build你的应用程序,你没有做任何事情来访问多台机器。 所以,你可以扩展到单个机器上的核心数量(随着时间的推移,这个数量将会相当多),但是要真正达到networking规模,无论如何你都需要解决多机器问题。
如果你想使用多核, pyprocessing定义了一个基于进程的API来做真正的并行化。 PEP还包括一些有趣的基准。
Python是一种相当简单的语言,但有一些注意事项。 您需要了解的最重要的事情是全球口译员locking。 这只允许一个线程访问解释器。 这意味着两件事情:1)你很less发现自己在Python中使用锁语句,2)如果你想利用多处理器系统,你必须使用单独的进程。 编辑:我也应该指出,你可以把一些代码在C / C + +,如果你想要绕过GIL以及。
因此,你需要重新考虑你为什么要使用线程。 如果您希望将应用程序并行化以利用双核架构,则需要考虑将应用程序分成多个进程。
如果你想提高响应能力,你应该考虑使用线程。 还有其他的select,即微读 。 还有一些你应该研究的框架:
- 无堆栈的python
- greenlets
- GEVENT
- 单片眼镜
下面是一个基本的线程示例。 它会产生20个线程; 每个线程将输出其线程号。 运行它并观察它们的打印顺序。
import threading class Foo (threading.Thread): def __init__(self,x): self.__x = x threading.Thread.__init__(self) def run (self): print str(self.__x) for x in xrange(20): Foo(x).start()
正如你所暗示的,Python线程是通过时间切片来实现的。 这是他们如何得到“平行”的效果。
在我的例子中,我的Foo类扩展了线程,然后实现了run
方法,这是你想要在一个线程中运行的代码。 要启动线程,请在线程对象上调用start()
,它将自动调用run
方法…
当然,这只是非常基础的。 您最终将需要了解信号量,互斥锁和线程同步和消息传递的locking。
如果单个工作人员正在执行I / O绑定操作,请在Python中使用线程。 如果您试图跨越机器上的多个核心进行扩展,请为Pythonfind一个好的IPC框架,或者select一种不同的语言。
GIL的一个简单的解决scheme是多处理模块。 它可以用来代替线程模块,但使用多个解释器进程而不是线程。 正因为如此,对于简单的事情来说,比普通的线程有更多的开销,但是如果你需要的话,它给你提供了真正的并行化的优势。 它也可以轻松扩展到多台物理机器。
如果你需要真正的大规模并行比我看得更远,但如果你只是想扩展到一台计算机的所有内核或几个不同的核心,没有所有的工作,将实施一个更全面的框架,比这是给你。
试着记住,GIL被设置为每隔一段时间轮询一次以显示多个任务的外观。 这个设置可以很好地调整,但是我提出的build议是,应该有线程正在做的工作或大量的上下文切换会导致问题。
我甚至会build议在处理器上的多个父母,并尽量保持在同一个核心上的工作。