Python學習--day33-多執行緒
阿新 • • 發佈:2019-01-02
day 34
一、多執行緒
1、什麼是執行緒
執行緒即程式的執行線路,相當於一條流水線,它包含了程式的具體執行步驟。
多執行緒(即多個控制執行緒)的概念是,在一個程序中存在多個控制執行緒,多個控制執行緒共享該程序的地址空間,相當於一個車間內有多條流水線,都共用一個車間的資源。
2、執行緒與程序之間的關係
程序中包含了執行該程式的所需要的所有資料,程序是一個資源單位,執行緒是CPU的最小執行單位,每一個程序一旦被建立,就預設開啟了一條執行緒,稱之為主執行緒。一個程序可以包含多個執行緒,程序包含執行緒,執行緒依賴程序。
3、為什麼使用執行緒
為了體高程式的效率(使cpu在一個程序內進行切換),相比於多程序而已,多執行緒佔用更少的作業系統資源。
4、開啟多執行緒的兩種方式:
# 開啟執行緒的第一種方式 from threading import Thread from multiprocessing import Process def task(): print("threading running!") t1 = Thread(target=task) t1.start() print("over") # 第二種方式 class MyThread(Thread): def run(self): print("子執行緒 running....") MyThread().start()print("over2") # 對比程序啟動時間 # from multiprocessing import Process # # def task(): # print("threading running!") # if __name__ == '__main__': # # t1 = Process(target=task) # t1.start() # # print("over")
5、程序和執行緒的區別: 1.程序對於作業系統的資源耗費非常高,而執行緒非常低(比程序低10-100倍); 2.在同一個程序中,多個執行緒之間資源是共享的。
###執行緒與程序對比示例一: from threading import Thread from multiprocessing import Process import os def work(): print('hello') if __name__ == '__main__': #在主程序下開啟執行緒 t=Thread(target=work) t.start() print('主執行緒/主程序') ''' 列印結果: hello 主執行緒/主程序 ''' #在主程序下開啟子程序 t=Process(target=work) t.start() print('主執行緒/主程序') ''' 列印結果: 主執行緒/主程序 hello ''' ###執行緒與程序對比示例二: from multiprocessing import Process from threading import Thread import time def task(): # print("子程序任務....") pass # 100個程序時間統計 # if __name__ == '__main__': # start = time.time() # ps = [] # for i in range(100): # p = Process(target=task) # p.start() # ps.append(p) # for p in ps: # p.join() # print(time.time()-start) #100個執行緒 start = time.time() ts = [] for i in range(100): t = Thread(target=task) t.start() ts.append(t) for t in ts: t.join() print(time.time()-start)
6、守護執行緒
守護執行緒會等待主執行緒執行完畢後被銷燬
#1.對主程序來說,執行完畢指的是主程序程式碼執行完畢 #2.對主執行緒來說,執行完畢指的是主執行緒所在的程序內所有非守護執行緒統統執行完畢,主執行緒才算執行完畢 #1 主程序在其程式碼結束後就已經算執行完畢了(守護程序在此時就被回收),然後主程序會一直等非守護的子程序都執行完畢後回收子程序的資源(否則會產生殭屍程序),才會結束, #2 主執行緒在其他非守護執行緒執行完畢後才算執行完畢(守護執行緒在此時就被回收)。因為主執行緒的結束意味著程序的結束,程序整體的資源都將被回收,而程序必須保證非守護執行緒都執行完畢後才能結束。 from threading import Thread # # import time # # def task(): # print("sub thread run....") # time.sleep(3) # print("sub thread over....") # # t = Thread(target=task) # t.setDaemon(True) # t.start() # # # t = Thread(target=task) # t.setDaemon(True) # t.start() # # print("over!") from threading import Thread import time def task(): print("子執行緒執行。。。") time.sleep(1) print("子執行緒結束。。。") t = Thread(target=task) t.setDaemon(True) t.start() # time.sleep(0.1) print("over")
7、執行緒中常用的屬性
# Thread例項物件的方法 # isAlive(): 返回執行緒是否活動的。 # getName(): 返回執行緒名。 # setName(): 設定執行緒名。 # threading模組提供的一些方法: # threading.currentThread(): 返回當前的執行緒變數。 # threading.enumerate(): 返回一個包含正在執行的執行緒的list。正在執行指執行緒啟動後、結束前,不包括啟動前和終止後的執行緒。 # threading.activeCount(): 返回正在執行的執行緒數量,與len(threading.enumerate())有相同的結果。 from threading import Thread,current_thread,enumerate,active_count import os def task(): print("running..") # print(os.getpid()) # print(current_thread()) print(active_count()) t1 = Thread(target=task) t1.start() # print(t1.is_alive()) # print(t1.isAlive()) # print(t1.getName()) # 獲取所有執行緒物件列表 print(enumerate()) # 獲取當前執行緒物件 print(current_thread()) # 獲取當前正在執行的執行緒個數 print(active_count()) # t2 = Thread(target=task) # t2.start()
8、執行緒互斥鎖
當多個程序或執行緒同時修改同一份資料時,可能會造成資料的錯亂,所以必須要加鎖。
鎖的使用方法與程序中鎖的使用方法完全相同。
import time from threading import Thread,Lock lock =Lock() a = 100 def task(): lock.acquire() global a temp = a - 1 time.sleep(0.01) a = temp lock.release() ts = [] for i in range(100): t = Thread(target=task) t.start() ts.append(t) for t in ts: t.join() print(a)
9、訊號量
a、定義:訊號量也是一種鎖,他的特點是可以設定一個數據可以被幾個執行緒(程序)共享。 b、與普通鎖的區別:
普通鎖一旦加鎖,則意味著這個資料在同一時間只能被一個執行緒使用;而訊號量可以讓這個資料在統一時間被限定個數的多個程序使用。
from threading import Semaphore,Thread,current_thread import time,random sem = Semaphore(3) def task(): sem.acquire() print("%s run..." % current_thread()) time.sleep(3) sem.release() for i in range(10): t = Thread(target=task) t.start()
二、程序補充(守護程序的使用)
import time,random from multiprocessing import Process,JoinableQueue def eat_hotdog(name,q): while True: res = q.get() print("%s吃了%s" % (name,res)) time.sleep(random.randint(1,2)) q.task_done() #記錄已經被處理的資料的數量 def make_hotdog(name,q): for i in range(1,6): time.sleep(random.randint(1, 2)) print("%s生產了第%s個熱狗" % (name,i)) res = "%s的%s個熱狗" % (name,i) q.put(res) # q.put(None) if __name__ == '__main__': q = JoinableQueue() #生產者1 c1 = Process(target=make_hotdog,args=("萬達熱狗店",q)) c1.start() #生產者2 c2 = Process(target=make_hotdog, args=("老男孩熱狗店", q)) c2.start() # 消費者 p2 = Process(target=eat_hotdog,args=("思聰",q)) p2.daemon = True # 如果只是加這行程式碼,有可能會出現,熱狗沒吃完程式就結束了的情況,因此需要加上後面的p.join() p2.start() # 首先保證生產者全部產完成 c1.join() c2.join() # 保證佇列中的資料全部被處理了 q.join() # 明確生產方已經不會再生成資料了 # 等待放入佇列中的所有資料被取完後再往下執行