1. 程式人生 > >GIL 相關 和程序池

GIL 相關 和程序池

#GIL  (global interpreter Lock)

#全域性直譯器鎖 :鎖是為了避免資源競爭造成資料錯亂

#當一個py啟動後 會先執行主執行緒中的程式碼
#在以上程式碼中有啟動了子執行緒 子執行緒的任務還是執行程式碼
#直譯器在一個程序中只有一個(直譯器也是一堆程式碼)
#主線和子線都要去呼叫直譯器,就存在了競爭關係



#全域性直譯器鎖: 是為了防止多個執行緒同時使用python直譯器 一旦加鎖 將導致執行緒無法並行
#這個問題不是所有直譯器都存在 只有cpython(c寫的直譯器) 也就是說只有cpythonzhong
#有全域性直譯器鎖 如果是Jpython 就要參考Java的多執行緒實現
#python程式的執行:
#1.啟動直譯器程序 python.exe
#2.解析py檔案並執行它

# 每個py程式中都必須有直譯器參與 直譯器其實就是一堆程式碼
#相當於多個執行緒要呼叫同一個直譯器程式碼 共享變成競爭 競爭就要出事 給直譯器加互斥鎖

# python中記憶體管理依賴於GC(一段用於回收記憶體的程式碼) 也需要一個執行緒 除了自己開的線
# 程 系統還有一些內建執行緒 就算你的程式碼不會去競爭直譯器 內建執行緒也可能會競爭 所以
# 所以必須加上鎖

#當一個執行緒遇到了IO 同時直譯器也會自動解鎖 去執行其他執行緒 cpu會切換到其他程式
# 案例:
# from threading import Thread
# import time
# def task1():
# sum=1
# for i in range(10000000):
# sum+=i
# def task2():
# sum=1
# for i in range(10000000):
# sum+=i
# start=time.time()
# t1=Thread(target=task1)
# t2=Thread(target=task2)
# t1.start()
# t2.start()
# t1.join()
# t2.join()
# print(time.time()-start)

#直譯器加鎖以後:
#將導致所有執行緒只能併發 不能達到真正的並行 意味著同意時間只有一個cpu在處理你的
#執行緒 給你的感覺是小路低

#程式碼執行有兩種狀態;
#阻塞 i/o :失去cpu的執行權 (cpu等待I/O完成)
#非阻塞 :程式碼正常執行 比如迴圈一千萬次 中途cpu可能切換 但是很快會回來(cpu在計算)

#加入有32核cpu 要處理一個下載任務 網路速度慢 100k/s 檔案大小為1024kb 如果你的程式碼中
#IO操作非常多 cpu效能不能直接決定你的任務處理速度

#案例:
#目前有三個任務 每個任務處理需要一秒 獲取元資料需要一小時
#3個cpu 需要一小時一秒
#1個cpu 需要一小時三秒

#在IO密集的程式中 cpu效能無法直接決定程式的執行速度 python就應該幹這種活兒
#在計算密集的程式中 cpu效能可以直接決定程式的執行效率



#2.GIL與互斥鎖
#GIL與互斥鎖:
# from threading import Thread,Lock
# import time
# mutex=Lock()
# num = 1
# def task():
# global num
# mutex.acquire()
# temp=num
# time.sleep(1) #當執行緒中出現io時 GIL鎖就解開了
# num=temp+1
# mutex.release()
# t1=Thread(target=task,)
# t2=Thread(target=task,)
# t1.start()
# t2.start()
# t1.join()
# t2.join()
# print(num)
# #GIL和自定義互斥鎖的區別
# #全域性鎖不能保證自己的執行緒安全 但是保證直譯器中的資料安全
# #GIL線上程呼叫直譯器時 自動加鎖 IO阻塞時和執行緒程式碼執行完畢時 自動解鎖
#
#3.執行緒池與程序池
# 程序池: 就是一個裝程序的容器
# 為什麼出現: 當程序很多的時候方便管理程序
# 什麼時候用:當併發量特別大的時候 例如雙十一 很多時候程序是空閒的 就讓他進入程序池
#讓有任務處理的程序進入程序池
# 程序池:
# ProcessPoolExecutor
# 建立時指定最大程序數 自動建立程序
# 呼叫submit函式將任務提交到程序池中
# 建立程序是在呼叫submit後發生的
#舉例:
# #收發資料
# def task(c,addr):
# while True:
# data=c.recv(1024)
# print(data.decode("utf-8"))
# if not data:
# c.close()
# break
# c.send(data.upper())
# if __name__ == '__main__':
# import socket
# from concurrent.futures import ProcessPoolExecutor
# server=socket.socket()
# server.bind(("127.0.0.1",8091))
# server.listen(5)
# #建立一個程序池 預設
# pool=ProcessPoolExecutor()
# while True:
# c,addr = server.accept()
# pool.submit(task,c,addr)

#總結一下:
# 程序池可以自動建立程序
# 程序限制最大程序數
# 自動選擇一個空閒的程序幫你處理任務