[转载]python的全局锁
Queue模块
- 提供FIFO的Queue,LIFO的队列,优先队列,虽然Queue类是线程安全的,适用于多线程间安全的交换数据,内部使用了Lock和Condition,虽然Queue类的size加了锁,但是依然不能保证立即get,put就能成功,因为读取大小和get,put方法是分开的,在一个线程在读取或者操作时,可能会被其他线程抢占了资源.
GIL全局解释器锁
- CPython 在解释器进程级别有一把锁,叫做GIL,即全局解释器锁。
- GIL 保证CPython进程中,只有一个线程执行字节码。甚至是在多核CPU的情况下,也只允许同时只能有一个CPU上运行该进程的一个线程。(所以,Python中的多线程都是假并行的)
CPython中
-
IO密集型,某个线程阻塞,就会调度其他就绪线程;
-
CPU密集型,当前线程可能会连续的获得GIL,导致其它线程几乎无法使用CPU。
-
在CPython中由于有GIL存在,IO密集型,使用多线程较为合算;CPU密集型,使用多进程,要绕开GIL
-
python中绝大多数内置数据结构的读、写操作都是原子操作。
-
由于GIL的存在,Python的内置数据类型在多线程编程的时候就变成了安全的了,但是实际上它们本身不是线程安全类型
如下测试,
#IO密集型
import threading
import datetime
start = datetime.datetime.now()
def fn(x=1000000000):
count = 0
while count < x:
count += 1
print(threading.current_thread(),count)
thrad_list=[]
for i in range(5):
t = threading.Thread(target=fn,name='fn{}'.format(i+1))
t.start()
thrad_list.append(t)
for t in thrad_list:
t.join()
delta = (datetime.datetime.now()-start).total_seconds()
print(delta)
----------------------------------------------------------------
<Thread(fn2, started 10396)> 1000000000
<Thread(fn5, started 5988)> 1000000000
<Thread(fn1, started 13688)> 1000000000
<Thread(fn4, started 2068)> 1000000000
<Thread(fn3, started 15576)> 1000000000
225.282195
#CPU密集型
import datetime
import threading
start = datetime.datetime.now()
def fn(name,x=100000000):
count = 0
while count < x:
count += 1
print(name,count)
for i in range(5):
fn("{},fn{}".format(threading.current_thread(),1+1))
delta = (datetime.datetime.now()-start).total_seconds()
print(delta)
---------------------------------------------------------------
<_MainThread(MainThread, started 4648)>,fn2 1000000000
<_MainThread(MainThread, started 4648)>,fn2 1000000000
<_MainThread(MainThread, started 4648)>,fn2 1000000000
<_MainThread(MainThread, started 4648)>,fn2 1000000000
<_MainThread(MainThread, started 4648)>,fn2 1000000000
211.827783
#单线程是串行运行的
从上面两个例子看出,对于python中,CPU密集型用多线程写,跟串行没有什么区别,根本就体现不出来优势,原因搜索GIL存在.(可以使用多进程)
欢迎大家评论交流,发现博文中存在的问题一定要留言哦