GIL ä¸ Python 线ç¨ççº è
GIL æ¯ä»ä¹ä¸è¥¿ï¼å®å¯¹æ们ç python ç¨åºä¼äº§çä»ä¹æ ·çå½±åï¼æ们å æ¥çä¸ä¸ªé®é¢ãè¿è¡ä¸é¢è¿æ®µ python ç¨åºï¼CPU å ç¨çæ¯å¤å°ï¼
# 请å¿å¨å·¥ä½ä¸æ¨¡ä»¿ï¼å±é©:)def dead_loop(): while True: passdead_loop()
çæ¡æ¯ä»ä¹å¢ï¼å ç¨ 100ï¼ CPUï¼é£æ¯åæ ¸ï¼è¿å¾æ¯æ²¡æè¶ çº¿ç¨çå¤è£ CPUãå¨æçåæ ¸ CPU ä¸ï¼è¿ä¸ªæ»å¾ªç¯åªä¼åææä¸ä¸ªæ ¸çå·¥ä½è´è·ï¼ä¹å°±æ¯åªå ç¨ 50ï¼ CPUãé£å¦ä½è½è®©å®å¨åæ ¸æºå¨ä¸å ç¨ 100ï¼ ç CPU å¢ï¼çæ¡å¾å®¹ææ³å°ï¼ç¨ä¸¤ä¸ªçº¿ç¨å°±è¡äºï¼çº¿ç¨ä¸æ£æ¯å¹¶åå享 CPU è¿ç®èµæºçåãå¯æçæ¡è½ç¶å¯¹äºï¼ä½åèµ·æ¥å¯æ²¡é£ä¹ç®åãä¸é¢çç¨åºå¨ä¸»çº¿ç¨ä¹å¤åèµ·äºä¸ä¸ªæ»å¾ªç¯ç线ç¨
import threadingdef dead_loop(): while True: pass# æ°èµ·ä¸ä¸ªæ»å¾ªç¯çº¿ç¨t = threading.Thread(target=dead_loop)t.start()# 主线ç¨ä¹è¿å
¥æ»å¾ªç¯dead_loop()t.join()
æéçå®åºè¯¥è½åå°å ç¨ä¸¤ä¸ªæ ¸ç CPU èµæºï¼å¯æ¯å®é è¿è¡æ åµå´æ¯æ²¡æä»ä¹æ¹åï¼è¿æ¯åªå äº 50ï¼ CPU ä¸å°ãè¿åæ¯ä¸ºä»ä¹å¢ï¼é¾é python 线ç¨ä¸æ¯æä½ç³»ç»çåç线ç¨ï¼æå¼ system monitor ä¸æ¢ç©¶ç«ï¼è¿ä¸ªå äº 50% ç python è¿ç¨ç¡®å®æ¯æ两个线ç¨å¨è·ãé£è¿ä¸¤ä¸ªæ»å¾ªç¯ç线ç¨ä¸ºä½ä¸è½å 满åæ ¸ CPU èµæºå¢ï¼å ¶å®å¹åçé»æå°±æ¯ GILã
GIL çè¿·æï¼ç并快ä¹ç
GIL çå ¨ç§°ä¸º Global Interpreter Lock ï¼æå³å ¨å±è§£éå¨éãå¨ Python è¯è¨ç主æµå®ç° CPython ä¸ï¼GIL æ¯ä¸ä¸ªè´§çä»·å®çå ¨å±çº¿ç¨éï¼å¨è§£éå¨è§£éæ§è¡ä»»ä½ Python 代ç æ¶ï¼é½éè¦å è·å¾è¿æéæè¡ï¼å¨éå° I/O æä½æ¶ä¼éæ¾è¿æéãå¦ææ¯çº¯è®¡ç®çç¨åºï¼æ²¡æ I/O æä½ï¼è§£éå¨ä¼æ¯é 100 次æä½å°±éæ¾è¿æéï¼è®©å«ç线ç¨ææºä¼æ§è¡ï¼è¿ä¸ªæ¬¡æ°å¯ä»¥éè¿sys.setcheckinterval æ¥è°æ´ï¼ãæ以è½ç¶ CPython ç线ç¨åºç´æ¥å°è£ æä½ç³»ç»çåç线ç¨ï¼ä½ CPython è¿ç¨å为ä¸ä¸ªæ´ä½ï¼åä¸æ¶é´åªä¼æä¸ä¸ªè·å¾äº GIL ç线ç¨å¨è·ï¼å ¶å®ç线ç¨é½å¤äºçå¾ ç¶æçç GIL çéæ¾ãè¿ä¹å°±è§£éäºæ们ä¸é¢çå®éªç»æï¼è½ç¶æ两个æ»å¾ªç¯ç线ç¨ï¼èä¸æ两个ç©ç CPU å æ ¸ï¼ä½å 为 GIL çéå¶ï¼ä¸¤ä¸ªçº¿ç¨åªæ¯åçåæ¶åæ¢ï¼æ»ç CPU å ç¨çè¿ç¥ä½äº 50ï¼ ã
çèµ·æ¥ python å¾ä¸ç»ååãGIL ç´æ¥å¯¼è´ CPython ä¸è½å©ç¨ç©çå¤æ ¸çæ§è½å éè¿ç®ãé£ä¸ºä»ä¹ä¼æè¿æ ·ç设计å¢ï¼æçæ³åºè¯¥è¿æ¯åå²éçé®é¢ãå¤æ ¸ CPU å¨ 1990 年代è¿å±äºç±»ç§å¹»ï¼Guido van Rossum å¨åé python çæ¶åï¼ä¹æ³ä¸å°ä»çè¯è¨æä¸å¤©ä¼è¢«ç¨å°å¾å¯è½ 1000ï¼ ä¸ªæ ¸ç CPU ä¸é¢ï¼ä¸ä¸ªå ¨å±éæå®å¤çº¿ç¨å®å ¨å¨é£ä¸ªæ¶ä»£åºè¯¥æ¯æç®åç»æµç设计äºãç®åèåè½æ»¡è¶³éæ±ï¼é£å°±æ¯åéç设计ï¼å¯¹è®¾è®¡æ¥è¯´ï¼åºè¯¥åªæåéä¸å¦ï¼è没æ好ä¸ä¸å¥½ï¼ãæªåªæªç¡¬ä»¶çåå±å®å¨å¤ªå¿«äºï¼æ©å°å®å¾ç»è½¯ä»¶ä¸ç红å©è¿ä¹å¿«å°±è¦å°å¤´äºãçç 20 å¹´ä¸å°ï¼ä»£ç 工人就ä¸è½ææä» ä» é å级 CPU å°±è½è®©è软件è·çæ´å¿«äºãå¨å¤æ ¸æ¶ä»£ï¼ç¼ç¨çå è´¹åé¤æ²¡æäºãå¦æç¨åºä¸è½ç¨å¹¶åæ¤å¹²æ¯ä¸ªæ ¸çè¿ç®æ§è½ï¼é£å°±æè°çä¼è¢«æ·æ±°ã对软件å¦æ¤ï¼å¯¹è¯è¨ä¹æ¯ä¸æ ·ãé£ Python ç对çå¢ï¼
Python çåºå¯¹å¾ç®åï¼ä»¥ä¸ååºä¸åãå¨ææ°ç python 3 ä¸ä¾ç¶æ GILãä¹æ以ä¸å»æï¼åå åï¼ä¸å¤ä»¥ä¸å ç¹ï¼
欲ç»ç¥åï¼æ¥åèªå®«ï¼
CPython ç GIL æ¬ææ¯ç¨æ¥ä¿æ¤ææå ¨å±ç解éå¨åç¯å¢ç¶æåéçãå¦æå»æ GILï¼å°±éè¦å¤ä¸ªæ´ç»ç²åº¦çé对解éå¨çä¼å¤å ¨å±ç¶æè¿è¡ä¿æ¤ãæè éç¨ Lock-Free ç®æ³ãæ 论åªä¸ç§ï¼è¦åå°å¤çº¿ç¨å®å ¨é½ä¼æ¯åä½¿ç¨ GIL ä¸ä¸ªéè¦é¾çå¤ãèä¸æ¹å¨ç对象è¿æ¯æ 20 å¹´åå²ç CPython 代ç æ ï¼æ´ä¸è®ºæè¿ä¹å¤ç¬¬ä¸æ¹çæ©å±ä¹å¨ä¾èµ GILã对 Python 社åºæ¥è¯´ï¼è¿ä¸å¼äºæ¥åèªå®«ï¼éæ°æ¥è¿ã
å°±ç®èªå®«ï¼ä¹æªå¿ æåï¼
æä½ç人æ¾ç»åäºä¸ä¸ªéªè¯ç¨ç CPythonï¼å° GIL å»æï¼å å ¥äºæ´å¤çç»ç²åº¦éãä½æ¯ç»è¿å®é çæµè¯ï¼å¯¹å线ç¨ç¨åºæ¥è¯´ï¼è¿ä¸ªçæ¬æå¾å¤§çæ§è½ä¸éï¼åªæå¨å©ç¨çç©ç CPU è¶ è¿ä¸å®æ°ç®åï¼æä¼æ¯ GIL çæ¬çæ§è½å¥½ãè¿ä¹é¾æªãå线ç¨æ¬æ¥å°±ä¸éè¦ä»ä¹éãåå°±é管çæ¬èº«æ¥è¯´ï¼é GIL è¿ä¸ªç²ç²åº¦çéè¯å®æ¯ç®¡çä¼å¤ç»ç²åº¦çéè¦å¿«çå¤ãèç°å¨ç»å¤§é¨åç python ç¨åºé½æ¯å线ç¨çãåè ï¼ä»éæ±æ¥è¯´ï¼ä½¿ç¨ python ç»ä¸æ¯å 为çä¸å®çè¿ç®æ§è½ãå°±ç®è½å©ç¨å¤æ ¸ï¼å®çæ§è½ä¹ä¸å¯è½å C/C++ æ¯è©ãè´¹äºå¤§åæ°æ GIL æ¿æï¼åè让大é¨åçç¨åºé½åæ ¢äºï¼è¿ä¸æ¯åè¾åè¾åã
é¾é Python è¿ä¹ä¼ç§çè¯è¨ççä» ä» å 为æ¹å¨å°é¾åæä¹ä¸å¤§å°±æ¾å¼å¤æ ¸æ¶ä»£äºåï¼å ¶å®ï¼ä¸åæ¹å¨ææéè¦çåå è¿å¨äºï¼ä¸ç¨èªå®«ï¼ä¹ä¸æ ·è½æåï¼
å ¶å®ç¥å
é£é¤äºåæ GIL å¤ï¼æç¶è¿ææ¹æ³è®© Python å¨å¤æ ¸æ¶ä»£æ´»çæ»æ¶¦ï¼è®©æ们åå°æ¬ææåçé£ä¸ªé®é¢ï¼å¦ä½è½è®©è¿ä¸ªæ»å¾ªç¯ç Python èæ¬å¨åæ ¸æºå¨ä¸å ç¨ 100ï¼ ç CPUï¼å ¶å®æç®åççæ¡åºè¯¥æ¯ï¼è¿è¡ä¸¤ä¸ª python æ»å¾ªç¯çç¨åºï¼ä¹å°±æ¯è¯´ï¼ç¨ä¸¤ä¸ªåå«å 满ä¸ä¸ª CPU å æ ¸ç python è¿ç¨æ¥åå°ãç¡®å®ï¼å¤è¿ç¨ä¹æ¯å©ç¨å¤ä¸ª CPU ç好æ¹æ³ãåªæ¯è¿ç¨é´å åå°å空é´ç¬ç«ï¼äºç¸ååéä¿¡è¦æ¯å¤çº¿ç¨éº»ç¦å¾å¤ãææäºæ¤ï¼Python å¨ 2.6 éæ°å¼å ¥äº multiprocessingè¿ä¸ªå¤è¿ç¨æ ååºï¼è®©å¤è¿ç¨ç python ç¨åºç¼åç®åå°ç±»ä¼¼å¤çº¿ç¨çç¨åº¦ï¼å¤§å¤§åè½»äº GIL 带æ¥çä¸è½å©ç¨å¤æ ¸çå°´å°¬ã
è¿è¿åªæ¯ä¸ä¸ªæ¹æ³ï¼å¦æä¸æ³ç¨å¤è¿ç¨è¿æ ·éé级ç解å³æ¹æ¡ï¼è¿æ个æ´å½»åºçæ¹æ¡ï¼æ¾å¼ Pythonï¼æ¹ç¨ C/C++ãå½ç¶ï¼ä½ ä¹ä¸ç¨åçè¿ä¹ç»ï¼åªéè¦æå ³é®é¨åç¨ C/C++ åæ Python æ©å±ï¼å ¶å®é¨åè¿æ¯ç¨ Python æ¥åï¼è®© Python çå½ Pythonï¼C çå½ Cãä¸è¬è®¡ç®å¯éæ§çç¨åºé½ä¼ç¨ C 代ç ç¼å并éè¿æ©å±çæ¹å¼éæå° Python èæ¬éï¼å¦ NumPy 模åï¼ãå¨æ©å±éå°±å®å ¨å¯ä»¥ç¨ C å建åç线ç¨ï¼èä¸ä¸ç¨é GILï¼å åå©ç¨ CPU ç计ç®èµæºäºãä¸è¿ï¼å Python æ©å±æ»æ¯è®©äººè§å¾å¾å¤æãå¥½å¨ Python è¿æå¦ä¸ç§ä¸ C 模åè¿è¡äºéçæºå¶ : ctypes
å©ç¨ ctypes ç»è¿ GIL
ctypes ä¸ Python æ©å±ä¸åï¼å®å¯ä»¥è®© Python ç´æ¥è°ç¨ä»»æç C å¨æåºç导åºå½æ°ãä½ æè¦åçåªæ¯ç¨ ctypes åäº python 代ç å³å¯ãæé ·çæ¯ï¼ctypes ä¼å¨è°ç¨ C å½æ°åéæ¾ GILãæ以ï¼æ们å¯ä»¥éè¿ ctypes å C å¨æåºæ¥è®© python å åå©ç¨ç©çå æ ¸ç计ç®è½åã让æ们æ¥å®é éªè¯ä¸ä¸ï¼è¿æ¬¡æä»¬ç¨ C åä¸ä¸ªæ»å¾ªç¯å½æ°
extern"C"{ void DeadLoop() { while (true); }}ç¨ä¸é¢ç C 代ç ç¼è¯çæå¨æåº libdead_loop.so ï¼Windows ä¸æ¯ dead_loop.dllï¼
ï¼æ¥çå°±è¦å©ç¨ ctypes æ¥å¨ python é load è¿ä¸ªå¨æåºï¼åå«å¨ä¸»çº¿ç¨åæ°å»ºçº¿ç¨éè°ç¨å ¶ä¸ç DeadLoop
from ctypes import *from threading import Threadlib = cdll.LoadLibrary("libdead_loop.so")t = Thread(target=lib.DeadLoop)t.start()lib.DeadLoop()è¿ååçç system monitorï¼Python 解éå¨è¿ç¨æ两个线ç¨å¨è·ï¼èä¸åæ ¸ CPU å ¨è¢«å 满äºï¼ctypes ç¡®å®å¾ç»åï¼éè¦æéçæ¯ï¼GIL æ¯è¢« ctypes å¨è°ç¨ C å½æ°åéæ¾çãä½æ¯ Python 解éå¨è¿æ¯ä¼å¨æ§è¡ä»»æä¸æ®µ Python 代ç æ¶é GIL çãå¦æä½ ä½¿ç¨ Python ç代ç å为 C å½æ°ç callbackï¼é£ä¹åªè¦ Python ç callback æ¹æ³è¢«æ§è¡æ¶ï¼GIL è¿æ¯ä¼è·³åºæ¥çãæ¯å¦ä¸é¢çä¾åï¼
extern"C"{ typedef void Callback(); void Call(Callback* callback) { callback(); }}注æè¿éä¸ä¸ä¸ªä¾åçä¸åä¹å¤ï¼è¿æ¬¡çæ»å¾ªç¯æ¯åçå¨ Python 代ç é (DeadLoop å½æ°) è C 代ç åªæ¯è´è´£å»è°ç¨è¿ä¸ª callback èå·²ãè¿è¡è¿ä¸ªä¾åï¼ä½ ä¼åç° CPU å ç¨çè¿æ¯åªæ 50ï¼ ä¸å°ãGIL åèµ·ä½ç¨äºã
å ¶å®ï¼ä»ä¸é¢çä¾åï¼æ们è¿è½çåº ctypes çä¸ä¸ªåºç¨ï¼é£å°±æ¯ç¨ Python åèªå¨åæµè¯ç¨ä¾ï¼éè¿ ctypes ç´æ¥è°ç¨ C 模åçæ¥å£æ¥å¯¹è¿ä¸ªæ¨¡åè¿è¡é»çæµè¯ï¼åªææ¯æå ³è¯¥æ¨¡å C æ¥å£çå¤çº¿ç¨å®å ¨æ¹é¢çæµè¯ï¼ctypes ä¹ä¸æ ·è½åå°ã
ç»è¯
è½ç¶ CPython ç线ç¨åºå°è£ äºæä½ç³»ç»çåç线ç¨ï¼ä½å´å 为 GIL çåå¨å¯¼è´å¤çº¿ç¨ä¸è½å©ç¨å¤ä¸ª CPU å æ ¸ç计ç®è½åã好å¨ç°å¨ Python æäºæç»çï¼multiprocessingï¼, å¸æ大æ³ï¼C è¯è¨æ©å±æºå¶ï¼åç¬å¤ä¹åï¼ctypesï¼ï¼è¶³ä»¥åºä»å¤æ ¸æ¶ä»£çææï¼GIL åè¿æ¯ä¸åå·²ç»ä¸éè¦äºï¼ä¸æ¯åã