实际上,不是,每个线程都是这个解释器的新线程。
它是由OS,而不是内部管理只是Python的虚拟机中的Python代码线程管理一个真正的线程。
需要GIL来防止非常基于OS的线程搞乱Python对象。
想象一个CPU上的一个线程和另一个CPU上的另一个线程。纯平行线程,用汇编写成。两者同时尝试更改注册表值。根本不可取的情况。访问相同内存位置的汇编指令最终会扰乱什么地点以及何时移动。最后,这种行为的结果可能很容易导致分段错误。那么,如果我们用C语言编写,C就控制这个部分,所以这不会发生在C代码中。 GIL对C级别的Python代码也一样。因此,实现Python对象的代码在更改它们时不会失去其原子性。想象一下,一个线程将一个值插入到另一个线程中正在向下移动的列表中,因为另一个线程从中移除了一些元素。没有GIL就会崩溃。
GIL对线程内的代码的原子性没有任何影响。它仅用于内部内存管理。
即使你有线程安全的对象,如双端队列(),如果你是在一次就可以了,无需额外的锁做一个以上的操作,就可以得到在两者之间插入另一个线程导致。和哎呀,问题发生!
咱们说一个线程需要的对象从堆栈,检查一下东西,如果条件是正确删除。
stack = [2,3,4,5,6,7,8]
def thread1():
while 1:
v = stack[0]
sleep(0.001)
if v%2==0: del stack[0]
sleep(0.001)
当然,这是愚蠢的,并应与stack.pop(0)来进行,以避免这种情况。但这是一个例子。
然后让另一个线程将每个0添加到堆栈。002秒:
def thread2():
while 1:
stack.insert(0, stack[-1]+1)
sleep(0.002)
现在,如果你这样做:
thread(thread2,())
sleep(1)
thread(thread1,())
会有一个时刻,尽管这不太可能,其中线程2()尝试线程1之间恰好叠加了新的项目()的检索和删除。因此,thread1()将删除一个新添加的项目,而不是正在检查的项目。结果不符合我们的意愿。所以,GIL不会控制我们在我们的线程中做什么,只是线程正在做什么 - 对于更基本的意义上的其他线程。
想象一下,你写了一个服务器来购买一些事件的票。两个用户连接并尝试同时购买同一张票。如果你不小心,用户可能会结束坐在另一个之上。
线程安全的对象是执行操作的对象,它不允许直到第一个完成的另一个动作发生。例如,如果您在一个线程中迭代deque(),并在另一个线程的中间另一个线程尝试追加某些内容,append()将会阻塞,直到第一个线程完成迭代为止。这是线程安全的。
某些操作需要多个指令进行同步,其中的Python之间可以通过不同的线程来解释。 GIL永远不会*同步Python程序,与asyncio无关。 - 它只是确保Python对象在C级别上是线程安全的,而不是在Python级别上。 –