线程在Python中是如何工作的,Python线程特有的常见陷阱是什么?
我一直在想Python中线程是如何工作的,很难找到关于线程如何工作的好信息。我可能只是缺少了一个链接或什么的,但官方文件似乎对这个问题不是很透彻,而且我还没有找到一篇好的评论 据我所知,一次只能运行一个线程,活动线程每隔10条指令左右切换一次线程在Python中是如何工作的,Python线程特有的常见陷阱是什么?,python,multithreading,Python,Multithreading,我一直在想Python中线程是如何工作的,很难找到关于线程如何工作的好信息。我可能只是缺少了一个链接或什么的,但官方文件似乎对这个问题不是很透彻,而且我还没有找到一篇好的评论 据我所知,一次只能运行一个线程,活动线程每隔10条指令左右切换一次 哪里有好的解释,或者你能提供一个吗?了解在Python中使用线程时遇到的常见问题也很好。下面是一个基本的线程示例。它将产生20个线程;每个线程将输出其线程编号。运行它并观察它们的打印顺序 import threading class Foo (thread
哪里有好的解释,或者你能提供一个吗?了解在Python中使用线程时遇到的常见问题也很好。下面是一个基本的线程示例。它将产生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类扩展了thread,然后实现了run
方法,这就是您希望在线程中运行的代码所在的位置。要启动线程,请在thread对象上调用start()
,该对象将自动调用run
方法
当然,这只是最基本的。您最终会想了解线程同步和消息传递的信号量、互斥量和锁。Python是一种非常容易执行线程的语言,但有一些注意事项。您需要知道的最大的事情是全局解释器锁。这只允许一个线程访问解释器。这意味着两件事:1)在python中很少使用lock语句;2)如果要利用多处理器系统,必须使用单独的进程。编辑:我还应该指出,如果您也想绕过GIL,可以将一些代码放在C/C++中 因此,您需要重新考虑为什么要使用线程。如果你想使你的应用程序并行化以利用双核架构,你需要考虑把你的应用程序分成多个进程。 <>如果你想提高响应性,你应该考虑使用线程。不过,还有其他选择,即。您还应该研究一些框架:
是的,由于全局解释器锁(GIL),一次只能运行一个线程。以下是一些关于这方面的见解的链接:
如果要使用多核,请定义一个基于进程的API来执行真正的并行化。还包括一些有趣的基准测试。如果单个工人正在执行I/O绑定操作,则使用python中的线程。如果您试图在一台机器上跨多个内核进行扩展,请为python找到一个好的框架或选择一种不同的语言。请记住,GIL设置为每隔一段时间轮询一次,以便显示多个任务的外观。这个设置可以微调,但我建议线程应该做一些工作,否则大量的上下文切换将导致问题
我甚至建议在处理器上使用多个父处理器,并尝试将类似的作业保留在同一个核心上。GIL的一个简单解决方案是模块。它可以作为线程模块的替代品,但使用多个解释器进程而不是线程。正因为如此,对于简单的事情来说,它的开销比普通线程稍微多一些,但是如果需要的话,它提供了真正并行化的优势。 它还可以轻松地扩展到多台物理机器
如果你真的需要大规模并行化,我会看得更远,但是如果你只想扩展到一台计算机的所有核心或几个不同的核心,而不需要所有的工作来实现一个更全面的框架,这是给你的。注意:无论我在哪里提到
thread
我都是指python中的线程,直到明确说明为止
如果您来自C/C++
background,那么线程在python中的工作方式会略有不同。在python中,在给定的时间内只能有一个线程处于运行状态。这意味着python中的线程无法真正利用多个处理内核的功能,因为按照设计,线程不可能在多个内核上并行运行
由于python中的内存管理不是线程安全的,因此每个线程都需要独占访问python解释器中的数据结构。这种独占访问是通过一种称为GIL(全局解释器锁)的机制获得的
python为什么使用GIL?
以防止多个线程同时访问解释器状态并破坏解释器状态
其思想是每当执行一个线程时(即使它是主线程),都会获取一个GIL,并在某个预定义的时间间隔之后执行
GIL由当前线程释放,并由其他线程(如果有的话)重新获取
为什么不干脆删除GIL?
这并不是说不可能删除GIL,而是因为在这样做的过程中,我们最终在内部设置了多个锁