標籤:子進程 rom 設定 基於 multi bre break erp sha
本節內容
- 什麼是線程
- 線程與進程的區別
- 開啟線程的兩種方式
- Thread對象的其他屬性或方法
- 守護線程
- GIL全域解譯器鎖
- 死結和遞迴鎖
- 訊號量 event 計時器
- 線程queue
一 什麼是線程
線程相對於進程更為輕量級,當一個進程啟動同時也會啟動一個主線程,多線程就是指在一個進程下建立多個線程並且這些線程共用地址空間。所以進程只是用來把資源集中到一起(進程只是一個資源單位,或者說資源集合),而線程才是cpu上的執行單位。
二 線程與進程的區別
1 Threads share the address space of the process that created it; processes have their own address space.
2 Threads have direct access to the data segment of its process; processes have their own copy of the data segment of the parent process.
3 Threads can directly communicate with other threads of its process; processes must use interprocess communication to communicate with sibling processes.
4 New threads are easily created; new processes require duplication of the parent process.
5 Threads can exercise considerable control over threads of the same process; processes can only exercise control over child processes.
6 Changes to the main thread (cancellation, priority change, etc.) may affect the behavior of the other threads of the process; changes to the parent process does not affect child processes.
總結上述區別,無非兩個關鍵點,這也是我們在特定的情境下需要使用多線程的原因:
同一個進程內的多個線程共用該進程內的地址資源
建立線程的開銷要遠小於建立進程的開銷(建立一個進程,就是建立一個車間,涉及到申請空間,而且在該空間內建至少一條流水線,但建立線程,就只是在一個車間內造一條流水線,無需申請空間,所以建立開銷小)
三 開啟線程的兩種方式開啟線程的方式
方式一from threading import Threadimport timedef sayhi(name): time.sleep(2) print(‘%s say hello‘ %name) if __name__ == ‘__main__‘: t=Thread(target=sayhi,args=(‘harry‘,)) t.start() print(‘主線程‘)方式二from threading import Threadimport timeclass Sayhi(Thread): def __init__(self,name): super().__init__() self.name=name def run(self): time.sleep(2) print(‘%s say hello‘ % self.name)if __name__ == ‘__main__‘: t = Sayhi(‘harry‘) t.start()
基於多進程多線程實現通訊端通訊
1 import socket 2 from multiprocessing import Process 3 from threading import Thread 4 5 def create_socket(): 6 server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 7 server.bind((‘127.0.0.1‘, 8080)) 8 server.listen(5) 9 return server10 11 def talk(conn):12 13 while True:14 try:15 data = conn.recv(1024)16 if data is None:break17 conn.send(data.upper())18 except ConnectionError:19 break20 conn.close()21 22 def communication(server):23 24 while True:25 conn,add = server.accept()26 t = Thread(target=talk, args=(conn,))27 t.start()28 29 if __name__ == ‘__main__‘:30 server = create_socket()31 p1 = Process(target=communication, args=(server,))32 p2 = Process(target=communication, args=(server,))33 p1.start()34 p2.start()
View Code編寫一個簡單的文本處理工具,具備三個任務,一個接收使用者輸入,一個將使用者輸入的內容格式化成大寫,一個將格式化後的結果存入檔案
1 from threading import Thread 2 msg_l = [] 3 format_l = [] 4 5 def user_input(): 6 while True: 7 text = input(‘請輸入內容:‘) 8 if text is None:continue 9 msg_l.append(text)10 11 12 def format_text():13 while True:14 if msg_l:15 reg = msg_l.pop()16 format_l.append(reg.upper())17 18 def save():19 while True:20 if format_l:21 with open(‘db1.txt‘,‘a‘,encoding=‘utf-8‘) as f:22 res = format_l.pop()23 f.write(‘%s\n‘ %res)24 f.flush()25 26 if __name__ == ‘__main__‘:27 28 t1 = Thread(target=user_input)29 t2 = Thread(target=format_text)30 t3 = Thread(target=save)31 32 t1.start()33 t2.start()34 t3.start()
View Code
四 Thread對象的其他屬性或方法
Thread執行個體對象的方法 # isAlive(): 返回線程是否活動的。 # getName(): 返回線程名。 # setName(): 設定線程名。
threading模組提供的一些方法: # threading.currentThread(): 返回當前的線程變數。 # threading.enumerate(): 返回一個包含正在啟動並執行線程的list。正在運行指線程啟動後、結束前,不包括啟動前和終止後的線程。 # threading.activeCount(): 返回正在啟動並執行線程數量,與len(threading.enumerate())有相同的結果。
五 守護線程
無論是進程還是線程,都遵循:守護xxx會等待主xxx運行完畢後被銷毀
需要強調的是:運行完畢並非終止運行
1、對主進程來說,運行完畢指的是主進程代碼運行完畢
2、對主線程來說,運行完畢指的是主線程所在的進程內所有非守護線程統統運行完畢,主線程才算運行完畢
詳細解釋:
1、主進程在其代碼結束後就已經算運行完畢了(守護進程在此時就被回收),然後主進程會一直等非守護的子進程都運行完畢後回收子進程的資源(否則會產生殭屍進程),才會結束,
2、主線程在其他非守護線程運行完畢後才算運行完畢(守護線程在此時就被回收)。因為主線程的結束意味著進程的結束,進程整體的資源都將被回收,而進程必須保證非守護線程都運行完畢後才能結束。
思考下述代碼的執行結果有可能是哪些情況?為什嗎?
from threading import Threadimport timedef foo(): print(123) time.sleep(1) print("end123")def bar(): print(456) time.sleep(3) print("end456")if __name__ == ‘__main__‘: t1=Thread(target=foo) t2=Thread(target=bar) t1.daemon=True t1.start() t2.start() print("main-------")以上代碼首先會輸出 123,456,main, 隨後會輸出end123,end456。因為t1守護的是主進程,讓主進程執行完print("main-------")線程2已經在運行了所以主進程並沒有結束,等到子線程運行完畢才會回收子進程的資源進程才會結束
Python並發編程之多線程