1. 程式人生 > >python中的多程序,多執行緒,死鎖,多協程

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(生成器)實現的,有點類似有多層函式的引用,一層一層執行下去,多協程消耗的資源極少.