日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

GIL,同步与异步

發布時間:2024/6/30 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 GIL,同步与异步 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Python GIL

1、GIL全局解釋器鎖

2、GIL全局解釋器鎖VS互斥鎖

3、定時器

?

1GIL全局解釋器鎖:

GIL全局解釋器鎖是一把互斥鎖,都是讓多個并發線程同一時間只能由一個執行

有了GIL的存在,同一進程內的多個線程同一時間只能有一個在運行,意味著在Cpython中一個進程下多個線程無法實現并行=>意味著無法利用多核優勢

但不影響并發的實現

注意:保護不同的數據安全,就應該加不同的鎖

為何要用GIL

因為Cpython解釋器自帶垃圾回收機制,并不是讓線程安全的。(原因在于垃圾回收機制會將線程馬上要引用值前,回收一個當前并沒有綁定的值,線程后面將引用時無法查找到)(Cpython解釋器的代碼會收到參數,而參數是線程)

如何使用:

GIL是加在Cpython解釋器之上,GIL可以比喻成執行權限,同一進程下的所有線程都是先在搶GIL,拿到執行權限,然后將代碼交給解釋器的代碼去執行,保證python解釋器同一時間只能執行一個任務的代碼

?

2GIL全局解釋器鎖VS互斥鎖

?

GIL保護的是解釋器級的數據,保護用戶自己的數據則需要自己加鎖處理

一切都由操作系統監視,最開始所有線程搶GIL,搶到后如果沒有用戶設鎖,那么遇到IO后,操作系統會將線程的cpu拿走,Cpython解釋器釋放其GIL,其他線程可以繼續搶GIL執行。當前面那個被系統解放GIL的線程再次搶到GIL時,會接著上次被解放的地方繼續運行下去。

如果用戶有加互斥鎖:

那么最開始的時候還是一樣都先搶GIL全局解釋器鎖,搶到的運行到用戶的互斥鎖地方拿到鎖后遇到IO會進行睡眠,此時操作系統會將GIL全局解釋器鎖釋放,別的線程搶到遇到用戶的互斥鎖沒法繼續運行下去,因為互斥鎖被睡眠的線程拿著,所以他們會被操作系統釋放GIL繼續搶,一直到睡眠的線程運行結束釋放互斥鎖后其他搶到GIL全局解釋器鎖的線程才可以從互斥鎖地方運行下去。

(GIL相當于執行權限,會在任務無法執行的情況,被強行釋放

自定義互斥鎖即便時無法執行,也不會自動釋放)

4、有兩種并發解決方案:

多進程:計算密集型

多線程:IO密集型

計算密集型

from multiprocessing import Process from threading import Thread import os,timedef work1():res=0for i in range(100000):res*=i def work2():res=0for i in range(100000):res*=i def work3():res=0for i in range(100000):res*=i def work4():res=0for i in range(100000):res*=i def work5():res=0for i in range(100000):res*=i def work6():res=0for i in range(100000):res*=i def work7():res=0for i in range(100000):res*=i def work8():res=0for i in range(100000):res*=i if __name__ == '__main__':# print(os.cpu_count()) #本機為4核start=time.time()# p1=Process(target=work1)# p2=Process(target=work2)# p3=Process(target=work2)# p4=Process(target=work2)# p5=Process(target=work2)# p6=Process(target=work2)# p7=Process(target=work2)# p8=Process(target=work2)p1=Thread(target=work1)p2=Thread(target=work2)p3=Thread(target=work2)p4=Thread(target=work2)p5=Thread(target=work2)p6=Thread(target=work2)p7=Thread(target=work2)p8=Thread(target=work2)p1.start()p2.start()p3.start()p4.start()p5.start()p6.start()p7.start()p8.start()p1.join()p2.join()p3.join()p4.join()p5.join()p6.join()p7.join()p8.join()stop=time.time()print("run time is %s" %(stop-start))計算密集型 在運算簡單情況下線程比進程快,但是程序中的運算都是相對復雜,所以多進程要比多線程強

IO密集型

?

from multiprocessing import Process from threading import Thread import os,time def work1():time.sleep(5)def work2():time.sleep(5)def work3():time.sleep(5)def work4():time.sleep(5) def work5():time.sleep(5)def work6():time.sleep(5)def work7():time.sleep(5)def work8():time.sleep(5) if __name__ == '__main__':# print(os.cpu_count()) #本機為4核start=time.time()p1=Process(target=work1)p2=Process(target=work2)p3=Process(target=work2)p4=Process(target=work2)p5=Process(target=work2)p6=Process(target=work2)p7=Process(target=work2)p8=Process(target=work2)# p1=Thread(target=work1)# p2=Thread(target=work2)# p3=Thread(target=work2)# p4=Thread(target=work2)# p5=Thread(target=work2)# p6=Thread(target=work2)# p7=Thread(target=work2)# p8=Thread(target=work2) p1.start()p2.start()p3.start()p4.start()p5.start()p6.start()p7.start()p8.start()p1.join()p2.join()p3.join()p4.join()p5.join()p6.join()p7.join()p8.join()stop=time.time()print("run time is %s" %(stop-start))

?

定時器

from threading import Timer,current_thread def task(x):print("%s run ...." %x)print(current_thread().name)if __name__ == '__main__':t=Timer(3,task,args=(10,))#第一個是時間秒數,第二個是函數名,第三個是傳入值 t.start()print("")

進程優先級別:

import queue # 隊列:先進先出 q=queue.Queue(3) q.put(1) q.put(2) q.put(3)print(q.get()) print(q.get()) print(q.get())# 堆棧:先進后出 q=queue.LifoQueue() q.put(1) q.put(2) q.put(3) print(q.get()) print(q.get()) print(q.get())# 優先級隊列:優先級高先出來,數字越小,優先級越高 q=queue.PriorityQueue() q.put((3,'data1')) q.put((-10,'data2')) q.put((11,'data3'))print(q.get()) print(q.get()) print(q.get()) 打印順序: -10 3 11

1、什么時候用池:

池的功能是限制啟動的進程數或線程數,

什么時候應該限制

當并發的任務數遠遠超過了計算機的承受能力時,既無法一次性開啟過多的進程數或者線程數時,就應該用池的概念將開啟的進程數或者線程數限制在計算機可承受的范圍內

2、同步vs異步

同步、異步指的是提交任務的兩種方式

同步:提交完任務后就在原地等待,直到任務運行完畢后拿回到任務的返回值,再繼續運行下一行代碼

異步:提交完任務(綁定一個回調函數)后根本就不在原地等待,直接運行下一行代碼,等到任務有返回值后會自動觸發回調函數

from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor import os import time import randomdef task(n):print("%s run..." %os.getpid())time.sleep(10)return n**2def parse(res):print("...") if __name__ == '__main__':pool=ProcessPoolExecutor(9)#進程池默認是4,代表一次性回復個數,# 超過回復個數,后面誰空誰回復l=[]for i in range(1,12):future = pool.submit(task,i)l.append(future)pool.shutdown(wait=True)#shutdown關閉進程池入口for future in l:print(future.result())print("") 要運行結束后獲得結果,放在父進程中效果不夠理想 from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor import os import time import randomdef task(n):print("%s run..." %os.getpid())time.sleep(10)return n**2def parse(future):time.sleep(1)res=future.result()print("%s 處理了 %s" %(os.getpid(),res))if __name__ == '__main__':pool=ProcessPoolExecutor(9)#進程池默認是4,代表一次性回復個數,# 超過回復個數,后面誰空誰回復start=time.time()for i in range(1,12):future = pool.submit(task,i)future.add_done_callback(parse)#parse會在futrue有返回值時立刻觸發, pool.shutdown(wait=True)#shutdown關閉進程池入口stop=time.time()print("",os.getpid(),(stop-start)) 優化進程 from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor import os import time import randomdef task(n):print("%s run..." %os.getpid())time.sleep(10)return n**2def parse(future):time.sleep(1)res=future.result()print("%s 處理了 %s" %(os.getpid(),res))if __name__ == '__main__':pool=ThreadPoolExecutor(9)# 線程池是cpu*5個數,代表一次性回復個數,# 超過回復個數,后面誰空誰回復start=time.time()for i in range(1,12):future = pool.submit(task,i)future.add_done_callback(parse)#parse會在futrue有返回值時立刻觸發, pool.shutdown(wait=True)#shutdown關閉進程池入口stop=time.time()print("",os.getpid(),(stop-start)) 優化線程

通過對比在有IO的情況下,線程要比進程快

?

轉載于:https://www.cnblogs.com/yf18767106368/p/9323113.html

總結

以上是生活随笔為你收集整理的GIL,同步与异步的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。