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()