dan*_*vic 7 python multithreading gil locks python-multiprocessing
我知道Python线程一次只能执行一个字节码,那么为什么线程库会提供锁?我假设如果一次只执行一个线程,则不会发生竞争条件.
该库提供锁,条件和信号量.这是同步执行的唯一目的吗?
更新:
我做了一个小实验:
from threading import Thread
from multiprocessing import Process
num = 0
def f():
global num
num += 1
def thread(func):
# return Process(target=func)
return Thread(target=func)
if __name__ == '__main__':
t_list = []
for i in xrange(1, 100000):
t = thread(f)
t.start()
t_list.append(t)
for t in t_list:
t.join()
print num
Run Code Online (Sandbox Code Playgroud)
基本上我应该启动100k线程并递增1.返回的结果是99993.
a)如果有GIL同步和避免竞争条件,结果如何不是99999?b)甚至可以启动100k OS线程吗?
看到答案后更新2:
如果GIL没有真正提供一种方法来执行简单的操作,例如原子递增,那么将它放在那里的目的是什么?它对于讨厌的并发问题没有帮助,那么它为什么要到位呢?我听说过C扩展的用例,有人会举例说明吗?
GIL同步字节码操作.一次只能执行一个字节代码.但是,如果您的操作需要多个字节码,则可以在字节码之间切换线程.如果您需要将操作设置为原子操作,那么您需要在GIL之上和之外进行同步.
例如,递增整数不是单个字节码:
>>> def f():
... global num
... num += 1
...
>>> dis.dis(f)
3 0 LOAD_GLOBAL 0 (num)
3 LOAD_CONST 1 (1)
6 INPLACE_ADD
7 STORE_GLOBAL 0 (num)
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)
这里花了四个字节码来实现num += 1.GIL不会确保x以原子方式递增.您的实验演示了问题:您丢失了更新,因为线程在LOAD_GLOBAL和STORE_GLOBAL之间切换.
GIL的目的是确保Python对象的引用计数以原子方式递增和递减.它并不是为了帮助您使用自己的数据结构.