python中的多程序,多執行緒,死鎖,多協程
本人根據自己的理解來總結的,如果有錯誤的地方還請各位大佬指正,謝謝了.
程序:程式是計算機可執行的二進位制資料,只有被作業系統呼叫的時候才開始它們的生命週期.程序就是程式的一次執行,擁有自己的地址空間,記憶體,程序id(pid),資料棧及其他記錄其執行軌跡的輔助資料;最小的資源分配單元.
多程序:使用多程序主要是為了實現多工,提高效率;在python 中的multiprocessing庫中Process類可用來建立子程序,子程序可以建立多個,但是全域性變數在多個程序中不能共享,也就是程序之間資源不能共享,因為它們都有自己的記憶體和資料棧;但是可以通過多程序庫提供的Queue佇列實現程序間的通訊.
import os import time from multiprocessing import Process num = 100 def run1(): global num print("子程序開始") time.sleep(2) print(num+100) print("子程序結束") if __name__ == "__main__": #可以使用os.getpid()獲得當前程序的id #可以用os.getppid()獲得當前程序父繼承id. print("主程序啟動,程序id為:%s"%(os.getpid())) # 建立一個子程序,可以建立多個程序 p = Process(target=run1) p.start() #程序阻塞,作用:等子程序結束,父程序再結束 p.join() time.sleep(1) print(num) print("主程序結束") #輸出結果: 主程序啟動,程序id為:4976 子程序開始 200 子程序結束 100 主程序結束
#程序間的通訊,需要用到佇列 import os import random import time from multiprocessing import Process,Queue def write(q): print("寫程序開始-%s"%(os.getpid())) for chr in ["A","B","C","D","E",]: q.put(chr) time.sleep(1) print("寫程序結束") def read(q): print("讀程序開啟-%s"%(os.getpid())) while True: value = q.get(True) print(value) print("讀程序結束") if __name__ == "__main__": print("主程序開始") # 在主程序中建立程序佇列 q = Queue() #建立讀寫程序 pw = Process(target=write,args=(q,)) pr = Process(target=read,args=(q,)) #啟動讀寫程序 pw.start() pr.start() # 寫程序結束 pw.join() #pr程序使被動地結束,在寫程序結束後,讀程序被強制結束 pr.terminate() print("主程序結束") #輸出結果: 主程序開始 寫程序開始-8768 讀程序開啟-7220 A B C D E 寫程序結束 主程序結束
執行緒:執行緒是程式中一個單一的順序控制流程。程序內有一個相對獨立的、可排程的執行單元,是系統獨立排程和分派CPU的基本單位指令執行時的程式的排程單位;有就緒,阻塞,執行三種狀態;又叫輕型的程序,程序可以共享程序的資源,最小的執行單元.
多執行緒:在一個程序中同時執行多個不同的子任務,就是多執行緒.執行緒之間可以共享程序的資源,但是如果多個程序在對同一個變數進行操作,會把結果給整亂套;由此衍生出了執行緒鎖,阻止多執行緒的併發執行,確保一個執行緒可以從頭執行到結束,相當於區域性多執行緒,上鎖部分以單執行緒來執行.
-
死鎖:兩個或兩個以上的程序或者執行緒在執行過程中,由於競爭資源或者由於彼此通訊而造成的一種阻塞的現象,若無外力作用,它們都將無法推進下去,都處於無限的相互等待狀態.;
-
死鎖會導致執行緒掛起,只有通過作業系統取強制終止.
#執行緒的危害,由於共享資源,對一個變數進行操作胡出錯.
import threading
num = 100
#建立執行緒鎖
lock = threading.Lock()
#可以為每個執行緒繫結一個數據庫連線/http請求/使用者資訊,區分開對變數進行操作:需要宣告:local.變數名=值
local = threading.local()
#事件,event.wait()用於事件的阻塞,event.clear()用於事件的重置
event = threading.Event()
def run():
print("%s執行緒開始"%(threading.current_thread().name))
global num
for i in range(1000000):
#上鎖,上鎖後執行結果是正確的
lock.acquire()
try:
num += 100
num -= 100
finally:
#無論如何都要釋放鎖,否則會導致死鎖
lock.release()
'''
另外一種上鎖方式,推薦使用這種,減小忘記釋放鎖的情況
with lock:
num += 100
num -= 100
'''
print('%s執行緒結束'%(threading.current_thread().name))
if __name__ == "__main__":
print("程序開始了")
# 建立第一個執行緒
t1 = threading.Thread(target=run,name="執行緒1")
t2 = threading.Thread(target=run,name="執行緒2")
t1.start()
t2.start()
t1.join()
t2.join()
print("num=%s"%(num))
print("程序結束了")
#輸出結果:
程序開始了
執行緒1執行緒開始
執行緒2執行緒開始
執行緒1執行緒結束
執行緒2執行緒結束
num=300
程序結束了
#多程序排程器,由於多執行緒執行後的結果有隨機性,所以要按照一定順序的話需要一個多執行緒排程器,這個只是簡單的,複雜一點還需要深入研究
import threading
import time
#建立排程對像
con = threading.Condition()
def run1():
with con:
for i in range(0,10,2):
print(i)
time.sleep(1)
#執行完一個,等待,讓執行緒2進行
con.wait()
#通知執行緒2
con.notify()
def run2():
with con:
for i in range(1, 10, 2):
print(i)
time.sleep(1)
#執行完後通知執行緒1
con.notify()
#處於等待狀態
con.wait()
if __name__ == "__main__":
threading.Thread(target=run1,name=threading.current_thread().name).start()
threading.Thread(target=run2, name=threading.current_thread().name).start()
#輸出結果:
0
1
2
3
4
5
6
7
8
9
協程: 是為非搶佔式多工產生子程式的計算機程式元件,協程允許不同入口點在不同位置暫停或開始執行程式.看上去是子程式,但是可以在子程式內部中斷子程式,轉而去執行別的子程式,也就是cpu中斷.與執行緒相比,協程的效率極高,因為只有一個執行緒,不會發生變數的衝突,共享資源不需要加鎖,只需要判斷狀態.python對協程的支援是通過generator(生成器)實現的,有點類似有多層函式的引用,一層一層執行下去,多協程消耗的資源極少.