24
gil 那那那那 那那那那那 http://xiaorui.cc

python gil

Embed Size (px)

Citation preview

Page 1: python gil

gil 那些事儿峰云就她了

http://xiaorui.cc

Page 2: python gil

相关

什么是 python 解释器CPython vs pypy vs Jython

Page 3: python gil

gil

什么是 Global Interpreter Lock

Python 为什么会有 gil

gil 的优缺点关于 gil 的历史

Page 4: python gil

Thread A Thread B

O| | | | | | |-1

1. get the current length2. check if there’s room for more3. Append element4. Incrment the length by 1

Page 5: python gil

Python’ s 线程python 线程是系统线程的 .

POSIX threads (pthreads)

Windows threads

受内核来调度并切换上下文

Page 6: python gil

性能对比def go_count(n): while n > 0:

n -= 1COUNT = 100000000 # 100 milliongo_count(COUNT)

t1 = Thread(target=go_count,args=(COUNT//2,))t2 = Thread(target=go_count,args=(COUNT//2,))t1.start(); t2.start()t1.join(); t2.join()

thread only

thread two

cost 10s

cost 21s

Page 7: python gil

那么问题来了多线程为什么比单线程还慢 ?

python 解释器运行原理只有一个线程在 running

多线程 acquire lock 的消耗成本

Page 8: python gil

gil简单描述 :

拿到 gil 锁,谁就可以 running , 当释放 gil, send signal没拿到 gil 锁 , 休眠 . 内核调度到你 , 你如果没锁 , sleep and wait for a signal

什么时候释放锁 :IO Blockevery 100 tick force, default

gil 是 mutex + semaphore + condition

Page 9: python gil

check_connection(self);Py_BEGIN_ALLOW_THREADSr = mysql_real_query(&(self->connection), query, len);Py_END_ALLOW_THREADS

_mysql.c gil process

Page 10: python gil

scheduler I/O

I/O I/O I/O I/Orun run run run

acquirerelease

acquire

release

acquire

releaserelease

acquire

Page 11: python gil

scheduler counter

check

run 100 ticks run 100 ticks run 100 ticks

acquire release releaserelease

acquire

check

check

Change it using sys.setcheckinterval()

acquire

Page 12: python gil

what a checkPeriodic “check” is simple

The currently running thread …

reset the tick counter

run signal handler if this is main thread

relase the gil

Reacquires the gil

Page 13: python gil

A tick ?def go(): a = True for i in range(3): print i if a: print "xiaorui.cc" b = None c = 123

Page 14: python gil

wake upCondition Variable

等待 wake up 的线程队列enqueue

dequeuesignal

thread 5thread 3

thread 2

thread 7

thread 1

Page 15: python gil

t2 100 5351 ENTRYt2 100 5351 ACQUIREt2 100 5352 RELEASEt2 100 5352 ENTRYt2 100 5352 ACQUIREt2 100 5353 RELEASEt1 100 5353 ACQUIREt2 100 5353 ENTRYt2 38 5353 BUSYt1 100 5354 RELEASEt1 100 5354 ENTRYt1 100 5354 ACQUIREt2 79 5354 RETRYt1 100 5355 RELEASEt1 100 5355 ENTRYt1 100 5355 ACQUIREt2 73 5355 RETRYt1 100 5356 RELEASEt2 100 5356 ACQUIREt1 100 5356 ENTRYt1 24 5356 BUSYt2 100 5357 RELEASE

进入临界区

获取锁

释放锁

没拿到锁

重新尝试

Page 16: python gil

break to think

python 如何保证 list\dict 的操作原子性某个线程一直高比率拿到锁 ?

t1 时间片用完了 , kernel 把 t2 调度起来 , 但 gil 还在 t1 手里 ?

多线程都在一个 cpu core 上 ?

Page 17: python gil

suspended

100 tciks

check

os

signal wake

release

不公平竞争100 tciks

check

signal

suspended

100 tciks

T1

T2

threadcs

……

Page 18: python gil

不公平竞争Thread A (cpu 1)

多核

Thread B (cpu 2)

release gil

acquire gil

release gil

acquire gil

wakedacquire gil (fail)

wakedacquire gil (fail)

signale

signale

Page 19: python gil

suspended

100 tciks

check

new gil

100 tciksT1

T2cv_wait(gil,TIMEOUT)

timeout

signale

suspended

100 tciks

gil_drop_request = 1 gil_drop_request = 0

cv_wait(gil,TIMEOUT)

Page 20: python gil

那么 threading 场景由于有 gil 全局锁 , python 多线程的意义 ?

IO 密集 CPU 密集

python 的线程调度策略再次声明,解释器没有 thread 调度器

Page 21: python gil

特例 , Signal

当信号到达的时,解释器会按照每个 tick 都要 check. 直到 main thread 处理了 signal.

Page 22: python gil

绕过 gil

multiprocessing

python gil 存在于线程之间ctypes

调用 c 函数之前 , 会释放 gil

more … …

Page 23: python gil

kill gil

python 能否去掉 gil ?

如何实现 python 底层去 gil ?

去掉之后又会出现什么 ?

总结 : 值不值 , 成本 ?

Page 24: python gil

“Q & A”– 峰云就她了