python并发编程5-线程
生活随笔
收集整理的這篇文章主要介紹了
python并发编程5-线程
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一、復習
# 線程# 線程是進程中的執行單位# 線程是CPU調度的最小單位# 線程之間資源共享## 線程的開啟和關閉以及切換的時間開銷遠遠小于進程# 線程本身可以在同一時間使用多個CPU # threading# 使用方法類似于multiprocess # python與線程# CPython解釋器在解釋代碼中容易產生數據不安全的問題# GIL 全局解釋器 鎖的是線程二、守護線程
例子1:
例子2:
例子3:
原因分析:
# 守護進程隨著主進程代碼的執行結束而結束 # 守護線程會在主線程結束之后等待其他子線程的結束才結束 # 原因解析: # 1.對主進程來說,運行完畢指的是主進程代碼運行完畢 # 2.對主線程來說,運行完畢指的是主線程所在的進程內所有非守護線程統統運行完畢,主線程才算運行完畢# 1 主進程在其代碼結束后就已經算運行完畢了(守護進程在此時就被回收),# 然后主進程會一直等非守護的子進程都運行完畢后回收子進程的資源(否則會產生僵尸進程),才會結束, # 2 主線程在其他非守護線程運行完畢后才算運行完畢(守護線程在此時就被回收)。# 因為主線程的結束意味著進程的結束,進程整體的資源都將被回收,# 而線程必須保證非守護線程都運行完畢后才能結束。例子4:進程
例子5:守護線程
三、線程鎖
進程 多進程情況下一般不用加鎖。除非是操作文件之類的東西解決上述阻塞的辦法:加鎖
def func(lock):global nlock.acquire()temp=ntime.sleep(1)n=temp-1lock.release() n=10 t_lst=[] lock=Lock() for i in range(10):t=Thread(target=func,args=(lock,))t.start()t_lst.append(t) for t in t_lst:t.join() print(n)最終運行結果為:0
2、互斥鎖-科學家吃面問題-死鎖
只有一份面和一個叉子??茖W家公平競爭,就會有一個人拿到叉子,一個人拿到面。這就是典型的死鎖問題只有一份面和一個叉子??茖W家公平競爭,就會有一個人拿到叉子,一個人拿到面。這就是典型的死鎖問題
noodle_lock=Lock() fork_lock=Lock() def eat1(name):noodle_lock.acquire()print('%s拿到面條了'%name)fork_lock.acquire()print('%s拿到叉子了'%name)print('%s吃面'%name)fork_lock.release()noodle_lock.release() def eat2(name):fork_lock.acquire()print('%s拿到面條了'%name)time.sleep(1)noodle_lock.acquire()print('%s拿到叉子了'%name)print('%s吃面'%name)noodle_lock.release()fork_lock.release()Thread(target=eat1,args=('alex',)).start() Thread(target=eat2,args=('Egon',)).start() Thread(target=eat1,args=('bossjin',)).start() Thread(target=eat2,args=('nezha',)).start()運行結果:
2、解決互斥鎖問題-RLock介紹
4、解鎖科學家吃面問題-遞歸鎖
'''5 遞歸鎖''' # 解決死鎖問題,一個線程中可以acquire多次 noodle_lock=fork_lock=RLock() # 一個鑰匙串上的兩把鑰匙 def eat1(name):noodle_lock.acquire()print('%s拿到面條了'%name)fork_lock.acquire()print('%s拿到叉子了'%name)print('%s吃面'%name)fork_lock.release()noodle_lock.release() def eat2(name):fork_lock.acquire()print('%s拿到面條了'%name)time.sleep(1)noodle_lock.acquire()print('%s拿到叉子了'%name)print('%s吃面'%name)noodle_lock.release()fork_lock.release()Thread(target=eat1,args=('alex',)).start() Thread(target=eat2,args=('Egon',)).start() Thread(target=eat1,args=('bossjin',)).start() Thread(target=eat2,args=('nezha',)).start()運行結果:
四、信號量:控制多個線程同時訪問同一段代碼
from threading import Semaphore,Thread # 控制有多個線程訪問同一代碼 import time def func(sem,a,b):sem.acquire()time.sleep(1)print(a+b)sem.release() sem=Semaphore(4) for i in range(10):t=Thread(target=func,args=(sem,i,i+5))t.start()運行結果:
四個數字,四個數字輸出,最后輸出剩余2個
五、事件
# 事件被創建的時候:False狀態。導致wait()阻塞# True狀態 wait 非阻塞# clear 設置狀態為False# set 設置狀態為True # 數據庫 -文件夾 # 文件夾里有好多excel表格# 1.能夠更方便的對數據進行增刪查改# 2.安全訪問的機制 # 連接數據庫 # 檢測數據庫的可連接情況# 起兩個線程 # 第一個線程:連接數據庫# 等待一個信號 告訴我我們之間的網絡是通的# 連接數據庫 # 第二個線程:檢測與數據庫之間的網絡是否連通# time.sleep(0,2)# 將事件的狀態設置為True def db_connect(e):count=0while count<3:e.wait(1) # 狀態為False時,我只等待0.5s就結束if e.is_set():print('數據庫連接成功')breakelse:count+=1print('第%s次連接失敗'%count)# else:# raise TimeoutError('連接數據庫超時')def check_web(e):time.sleep(random.randint(0,3))e.set() e=Event() Thread(target=db_connect,args=(e,)).start() Thread(target=check_web,args=(e,)).start()?運行結果是隨機的
6、條件
# 條件 # acquire release # 一個條件被創建之初 默認有一個False 狀態 # False狀態會影響wait會一直處于等待狀態 # notify(int數據類型)造鑰匙 # 想用wait必須先acquire下condition相當于鎖,但是用完不還
def func(con,i):con.acquire()con.wait() # 等鑰匙print('在第%s個循環里'%i)con.release() con=Condition() for i in range(10):Thread(target=func,args=(con,i)).start() while True:num=int(input('>>>'))con.acquire()con.notify(num)con.release() # 用完鑰匙不會歸還?運行結果:
7、定時器:定時開啟線程
例子1:
def func():print('時間同步') Timer(2,func).start() # 等待兩秒開啟線程,異步 非阻塞 print(1234)例子2:
def func():print('時間同步') while True:Timer(2,func).start()time.sleep(2)運行結果:
每隔兩秒輸出一個時間同步。。
8、隊列
隊列的前提:
方法介紹:
隊列類型一:
q=queue.Queue() q.get() q.put_nowait() # 隊列滿后會報錯,進行異常處理 q.get() q.get_nowait() # 隊列中無數據時會報錯,進行異常處理 # 隊列:先進先出 # 隊列:線程安全的?隊列類型2-棧:
?
運行結果:
隊列類型3-優先級隊列:
q=queue.PriorityQueue() # 優先級隊列:先按值排序,再用ASCII排序 q.put((20,'a')) q.put((10,'b')) q.put((30,'c')) q.put((1,'e')) q.put((1,'d')) # 先出 print(q.get())運行結果:
9、線程池
# 線程池 # submit() 異步提交 # map(func,*iterables,timeout=None) 取代for循環submit操作 # shutdown(wait=True) # 相當于進程池的pool.close()+pool.join()# wait=True,等待池內所有任務執行完畢回收資源后才繼續 # wait=False,立即返回,并不會等待池內的任務執行完畢 # 但不管wait參數為何值,整個程序都會等到所有任務執行完畢 # submit和map必須在shutdown之前 # result 取得結果 # add_done_callback() 回調函數?例子1-submit應用:
from concurrent.futures import ThreadPoolExecutor import time '''1''' def func(n):time.sleep(2)print(n) tpool=ThreadPoolExecutor(max_workers=5) # 一般cpu個數乘5以內個線程 for i in range(10):tpool.submit(func,i) tpool.shutdown() # 等價于close+join功能 print('主線程') # 異步運行結果:
5個數5個數輸出
例子2:
?
運行結果:
例子3-map
def func(n):time.sleep(2)print(n)return n*n tpool=ThreadPoolExecutor(max_workers=5) # 一般cpu個數乘5以內個線程 tpool.map(func,range(8)) # 拿不到返回值?運行結果:
5個5個輸出
例子4-callback使用
def call_back(m):print('結果是 %s '%m.result()) def func(n):time.sleep(2)print(n)return n*n tpool=ThreadPoolExecutor(max_workers=5) # 一般cpu個數乘5以內個線程 for i in range(8):tpool.submit(func,i).add_done_callback(call_back)運行結果:
參考自http://www.cnblogs.com/Eva-J/articles/8306047.html
總結
以上是生活随笔為你收集整理的python并发编程5-线程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: opencv24-直方图比较
- 下一篇: Python-类与文件读取结合