1. 程式人生 > >python多程序,多執行緒,協程

python多程序,多執行緒,協程

 

執行緒依賴於程序,協程依賴於執行緒,效率最好的是協程,其次到執行緒,再到程序。總結:單執行緒會阻塞,協程不會阻塞。主要看會不會阻塞,其次看耗不耗資源。對比之下協程是最好的。

 

主執行緒結束,子執行緒才會結束。程式和程序通俗來講就是一個執行一個不執行,不執行的叫程式,執行起來的叫程序。程式只有一個,但是程序可以有多個,即是一個程式可以對應多個程序。程序是一個擁有資源的地方。資源是一個資源分配的地方。如一個qq,你執行起來,就是一個程序,就可以讓作業系統去排程,讓它擁有操作攝像頭,滑鼠,鍵盤等功能。

 

從執行緒和程序的角度來說,程序是資源分配的最小單位,執行緒是獨立排程的最小單位。
同一個程序中的多個執行緒之間可以併發執行,他們共享程序資源。
執行緒不擁有資源,執行緒可以訪問隸屬程序的資源,程序有自己的獨立空間地址,執行緒沒有自己的獨立空間地址,但是執行緒有自己的堆疊和區域性變數。

程序是系統程式執行和分配資源的基本單元。

執行緒是使用程序記憶體的空間,如QQ發訊息是執行緒,是QQ給它的資源。

程序建立的時候會把主程序的東西都複製一遍,即是把程式碼都複製一遍來執行,但是並不是完全相同,入程序號等。程式碼在執行的過程中不會改變,改變的是資料。子程序會把主程序的記憶體,程式碼,資源等都複製一遍。總結:相當於程式碼是共享的。

手機裡面的應用多開,就是多程序。程序先有才有執行緒。程序是資源分配的基本單位,執行緒是作業系統排程的基本單位。

真正執行的是執行緒。

程序與程序間是互相獨立的。socket 通過網路可以進行程序間的通訊,也可以通過檔案完成程序間的通訊(但是效率很低),和記憶體和磁碟的效率有關。

執行緒與程序的區別:必須有程序才能有執行緒,打個比方,程序就像車間裡面的流水線,執行緒就是流水線上的工人。那個流水線就是資源,用這個資源的就是執行緒(工人)。一條流水線上面可以安排一個工人在那生產產品,但是效率很低,也浪費了流水線的資源。多執行緒的意思就是一條流水線上面安排了很多工人在那生產產品,生產產品的效率顯然就會高很多,資源也得到了充分的利用。但是隨著業務的發展,一條流水線雖然安排滿了工人(即是程序裡面開啟了很多執行緒),還是無法滿足市場的需求,因為一條流水線上的資源有限(工位有限),你分配再多的工人也提高不了多大的效率,多分配的人只能在那裡閒著。所以想要提高效率,多生產產品,必須要多開幾條流水線(即是多程序)。然後幾條流水線一起生產產品,這樣效率就會大大提高。所以說程序是資源的分配單位,執行緒是排程單位。即是真正幹活的是執行緒(流水線工人),程序只是給執行緒提供資源(流水線工位)。必須有程序才有執行緒。執行緒不能獨立執行,必須依存在程序中。即是工人不能獨立地生成產品,必須依靠流水線才能完成一件產品的生產。一個QQ就是一個程序,它裡面有很多執行緒,來執行作業系統排程。

 

#_author:'DJS'
#date:2018-12-07
import time
import threading
import random
from queue import Queue
def coding():
    for i in range(3):
        print("正在寫程式碼%d"%i)
        time.sleep(1)

def huatu():
    for i in range(3):
        print("正在畫圖%d"%i)
        time.sleep(1)
def main():
    t1 = threading.Thread(target=coding) #這裡傳的時候是傳coding的並不是傳conding()的
    #傳coding()指的是傳一個函式的返回值(就是執行這個函式)
    t2 = threading.Thread(target=huatu)
    t1.start()
    t2.start()

VALUE = 0 #定義一個全域性變數
gLock = threading.Lock() #建立執行緒鎖

def add_value():
    global VALUE #在函式中引用或修改全域性變數,要用global註明
    gLock.acquire() #上鎖
    for i in range(1000000):  #執行緒執行的次數多,量大的時候,
        # 可能會造成執行緒不安全,造成資料 的錯誤。所以要對他進行上鎖,然後解鎖。
        #鎖只加在修改全域性變數的地方,對於那些訪問全域性變數的地方不用新增。對個執行緒
        #訪問全域性變數不會造成資料的錯誤
        VALUE+=1
    gLock.release() #解鎖
    print("最後執行完%d"%VALUE)

def main():
    for x in range(10): #這裡迴圈十次,表示的是add_value執行十次。
        t = threading.Thread(target=add_value)
        t.start()


##lock版的生成者與消費者模式
gMoney = 1000
gLock = threading.Lock() #建立一把鎖
gTotaltime = 10
gTime = 0
class Producer(threading.Thread):
    def run(self):
        global gMoney
        global gTime
        while True:
            monge = random.randint(100,1000) #隨機產生100到1000的整數
            gLock.acquire() #上鎖
            if gTime>=gTotaltime:
                gLock.release() #在braek之前想要解鎖。
                break #在這裡braek掉,但是加的鎖還沒有釋放,程式會一直被鎖死,執行不了其他的程式碼,braek的同時
                #也要解鎖
            gMoney+=monge
            print("%s生成了%d錢還剩%d錢"%(threading.current_thread(),monge,gMoney))
            gTime+=1
            gLock.release() #釋放鎖
            time.sleep(0.5)

class Consumer(threading.Thread):
    def run(self):
        global gMoney
        while True:
            money = random.randint(100,1000)
            gLock.acquire()
            if gMoney >= money:
                gMoney -= money
                print("%s消費者消費了%d元錢,剩餘%d元錢"%(threading.current_thread(),money,gMoney))

            else:
                if gTime>=gTotaltime:
                    gLock.release()
                    break  #如果生成者不生產了,就釋放鎖,然後退出
                print("%s消費者消費%d元錢,剩餘%d,不足"%(threading.current_thread(),money,gMoney))
            gLock.release()#解鎖不能放在if裡面,要對應起來放,要不然就成了死鎖
            time.sleep(0.5)

def main():
    for i in range(5):
        t = Producer(name="生成者執行緒%d"%i)
        t.start()

    for i in range(3):
        t = Consumer(name="消費者執行緒%d"%i)
        t.start()

##condition生產者與消費者模式

gMoney = 1000
gCondition = threading.Condition()#建立一把鎖
gTotaltime = 10
gTime = 0
class Producer(threading.Thread):
    def run(self):
        global gMoney
        global gTime
        while True:
            monge = random.randint(100,1000) #隨機產生100到1000的整數
            gCondition.acquire() #上鎖
            if gTime>=gTotaltime:
                gCondition.release() #在braek之前想要解鎖。
                break #在這裡braek掉,但是加的鎖還沒有釋放,程式會一直被鎖死,執行不了其他的程式碼,braek的同時
                #也要解鎖
            gMoney+=monge
            print("%s生成了%d錢還剩%d錢"%(threading.current_thread(),monge,gMoney))
            gTime+=1
            gCondition.notify_all() #生產完後就通知所有在等待的執行緒
            gCondition.release() #釋放鎖
            time.sleep(0.5)

class Consumer(threading.Thread):
    def run(self):
        global gMoney
        while True:
            money = random.randint(100,1000)
            gCondition.acquire()
            while gMoney < money:
                if gTime>=gTotaltime:
                    gCondition.release()
                    return #退出這個函式的所有層迴圈
                print("%s消費了%d元錢,還剩餘%d元錢,不足"%(threading.current_thread(),money,gMoney))
                gCondition.wait() #等待有錢的時候就釋放鎖
            gMoney-=money
            print("%s消費了%d元錢,剩餘%d元錢"%(threading.current_thread(),money,gMoney))
            gCondition.release()#解鎖不能放在if裡面,要對應起來放,要不然就成了死鎖
            time.sleep(0.5)

def main():
    for i in range(5):
        t = Producer(name="生成者執行緒%d"%i)
        t.start()

    for i in range(3):
        t = Consumer(name="消費者執行緒%d"%i)
        t.start()

##佇列
q = Queue(4) #建立4個佇列
q.put(1) #往佇列中新增一個元素
print(q.qsize()) #q.qsize獲取佇列中總共有多少個元素
print(q.empty())#判斷多了是否為空,是返回ture,不是空返回flase
print(q.full())#判斷佇列是否滿了
for i in range(4): #往佇列中新增4個數,這樣佇列就滿了
    q.put(i)
print(q.full())
for i in range(4):
    print(q.get()) #從佇列中拿資料出來,以先進先出的原則來拿

q.put(block=True) #,預設是阻塞式的,意思是往佇列裡面新增值
佇列如果滿了,就一直在那等,直到等到沒有滿
def set_value(q):
    index = 0
    while True:
        q.put(index)
        index+=1
        time.sleep(1) #每隔一秒就往佇列裡面新增值

def get_value(q):
    while True:
        print(q.get()) #獲取不到資料會一直在這裡等,直到等到上面那個佇列中新增有資料再列印
        #即是一直處於阻塞狀態

def main():
    q = Queue(6)
    t1 = threading.Thread(target=set_value,args=[q]) #建立一個執行緒,並這個方法裡面往裡面傳遞引數。
    t2 = threading.Thread(target=get_value,args=[q]) #這個個類建立物件
      t2 對於get_value 這個可以說是主執行緒,get_value 是子執行緒
       Thread是threading這個包的一個類
    t1.start() #主執行緒會等待子執行緒結束後再結束
    t2.start()
if __name__ == '__main__':
    main()


## 檢視程式中的執行緒數
def test1():
    for i in range(5):
        print("test1%d"%i)
        time.sleep(1)


def test2():
    for i in range(5):
        print("test2%d" % i)
        time.sleep(1)


def main():
    t1 = threading.Thread(target=test1) #target中指定一個執行緒名,那麼這個執行緒就去函式裡面執行了
    t2 = threading.Thread(target=test2)
    #target指定將來這個執行緒去那個函式執行程式碼
    #args指定將來呼叫函式的時候傳遞什麼資料過去,函式括號裡面可以隨便定義一個變數
    #接收傳遞過去的資料,不是把args作為變數作為函式接收資料的引數
    #多執行緒一般都是共享資料的,比如一個執行緒負責抓資料,一個執行緒負責處理資料,一個執行緒負責儲存資料
    #這樣通過共享資料就可以完成了資料的爬取,處理,儲存。
    t1.start()
    # time.sleep(1)
    # t2.start()
    # time.sleep(1)
    # #time.sleep(1)#設定延時,讓三個任務按照順序來執行,檢視執行緒數
    # while True:
    #     print(threading.enumerate())
    #     if len(threading.enumerate())<=1:
    #         break
    #一個執行緒的開始是在star()那裡開始的
    # #這是三個任務,執行的先後順序是作業系統說了算
    #作業系統可能先執行t1,也可以先執行t2,三個任務的執行順序是無序的
    #執行緒的執行是無序的,隨機的。所以想要三個任務按照順序來執行就要設定
    #延時了,分別在其他兩個那裡設定延時就可以按照順序執行了

if __name__ == '__main__':
    main()