我一直在努力地思考线程在Python中的工作方式,而且很难找到有关它们如何运行的良好信息。我可能只是缺少链接之类的东西,但似乎官方文档对该主题的了解不是很全面,而且我也找不到很好的文章。
据我所知,一次只能运行一个线程,活动线程每10条指令左右切换一次?
哪里有很好的解释,或者您可以提供一个解释?知道在Python中使用线程时遇到的常见问题也将非常高兴。
Answers:
是的,由于全局解释器锁定(GIL),一次只能运行一个线程。以下是一些有关此方面的见解的链接:
在最后一个链接中有一个有趣的报价:
让我解释一下这一切的含义。线程在同一虚拟机内运行,因此在同一物理机上运行。进程可以在同一台物理计算机上运行,也可以在另一台物理计算机上运行。如果您围绕线程构建应用程序,则您无济于事可访问多台计算机。因此,您可以扩展到一台计算机上的多个内核(随着时间的推移,内核数量会很多),但是要真正达到Web规模,则无论如何都需要解决多计算机问题。
如果要使用多核,则pyprocessing定义基于进程的API来进行真正的并行化。该PEP还包括了一些有趣的基准。
下面是一个基本的线程示例。它将产生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
方法...
当然,这只是最基本的知识。您最终将想要了解有关信号量,互斥量和线程同步和消息传递的锁的信息。
注意: 无论我在哪里提到,thread
我的意思是在明确声明之前专门在python中使用线程。
如果您来自C/C++
后台,线程在python中的工作方式会有所不同。在python中,给定时间只能有一个线程处于运行状态,这意味着python中的线程无法真正利用多个处理内核的功能,因为根据设计,线程不可能在多个内核上并行运行。
由于python中的内存管理不是线程安全的,因此每个线程都需要对python解释器中的数据结构进行独占访问。此独占访问是通过称为(全局解释器锁)的机制获取的。GIL
Why does python use GIL?
为了防止多个线程同时访问解释器状态并破坏解释器状态。
这个想法是,每当执行一个线程(即使它是主线程)时,都会获取一个GIL,并且在某个预定义的时间间隔后,当前线程会释放该GIL,而其他某个线程(如果有)会重新获取该GIL。
Why not simply remove GIL?
删除GIL并不是不可能的,只是这样做的目的是,我们最终在解释器中放置了多个锁以便对访问进行序列化,这甚至使单线程应用程序的性能降低。
因此删除GIL的成本是通过降低单线程应用程序的性能来弥补的,这是从未希望的。
So when does thread switching occurs in python?
GIL释放时会发生线程切换。那么GIL何时释放?有两种情况需要考虑。
如果线程正在执行CPU绑定操作(Ex图像处理)。
在旧版本的python中,线程切换通常是在固定数量的python指令之后发生的,默认情况下设置为。100
由于执行一条指令所花费的时间,决定何时应该进行切换并不是一个很好的策略从几毫秒甚至到一秒都可能非常疯狂100
。
在新版本中,不是使用指令计数作为度量标准来切换线程,而是使用了可配置的时间间隔。默认的切换间隔是5毫秒。您可以使用来获取当前的切换间隔sys.getswitchinterval()
。可以使用更改sys.setswitchinterval()
如果线程正在执行某些IO绑定操作(例如文件系统访问权限或
网络IO)
每当线程等待某些IO操作完成时,就会释放GIL。
Which thread to switch to next?
解释器没有自己的调度程序。在间隔结束时调度哪个线程是操作系统的决定。。