From 1a9cda80ff8379e3ff973ab3d0b014b6cef2d876 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A8=81=E5=8B=9D=20=E5=BC=B5?= Date: Fri, 19 Apr 2024 22:09:56 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9Ethread=20readme?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Thread/README.md | 282 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 282 insertions(+) diff --git a/Thread/README.md b/Thread/README.md index e69de29..06a27fa 100644 --- a/Thread/README.md +++ b/Thread/README.md @@ -0,0 +1,282 @@ +# 多工 +### 用到多工場合: +* 同時間須顯示許多資料 +* 讀取model和AI運算 +* 需要長時間掛在背景執行 +### 線程/進程 差異 +* 多線程(Thread) + + 簡單講:一個人有2隻手,然後可以同時進行 + +* 多進程(Process) + + 簡單講:聯合其他人一起做 +## +## 多線程 +### 正常使用 +#### 2個線程幾乎同時啟動 +``` +import threading +from queue import Queue #Thread 無法回傳值,所以要使用 Queue.put() 將要傳回的值存入 Queue,再用 Queue.get() 取出 +import time +import os +# A報數 +def A_Count_off(): + for i in range(0,5): + print(f'A : {i}') + time.sleep(0.5) + + +# B報數 +def B_Count_off(): + for i in range(5,10): + print(f'B : {i}') + time.sleep(0.5) + + + +thread_list=[A_Count_off,B_Count_off] +thread_num =[] +for i in range(0,len(thread_list)): + thread_num.append(threading.Thread(target=thread_list[i])) + +for i in range(0,len(thread_num)): + thread_num[i].join() + + +``` +### 非正常使用 +#### 第2個線程要等到第1個線程運行完才會啟動 +##### 失去多線程意義 +``` +# A報數 +def A_Count_off(): + for i in range(0,5): + print(f'A : {i}') + time.sleep(0.5) + + +# B報數 +def B_Count_off(): + for i in range(5,10): + print(f'B : {i}') + time.sleep(0.5) + + + +thread_list=[A_Count_off,B_Count_off] +thread_num =[] + +for i in range(0,len(thread_num)): + thread_num[i].start() + thread_num[i].join() + + +``` +### 攜帶參數 +``` +def Count_off(code_name): + print('process {} '.format(os.getpid())) + print('thread {} '.format(threading.current_thread().name)) + for i in range(0,5): + print(f'{code_name} : {i}') + time.sleep(0.5) + + +thread_name_list=["A","B","C","D"] + +thread_list=[] +for i in range(0,len(thread_name_list)): + thread_list.append(threading.Thread(target=Count_off,args=thread_name_list[i])) # 攜帶參數 +for i in range(0,len(thread_list)): + thread_list[i].start() +for i in range(0,len(thread_list)): + thread_list[i].join() + +``` + +### 使用class的方式(推薦使用) +#### 後續觀看程式碼及維護,會提高不少 +* start會使用分出去的線程 +* run會使用主線程 +``` +class Thread_class(threading.Thread): + def __init__(self,code_name): + threading.Thread.__init__(self) + self.code_name = code_name + + def run(self): + print('process {} '.format(os.getpid())) # 查看進程 + print('thread {} '.format(threading.current_thread().name)) # 查看線程 + for i in range(0,5): + print(f'{self.code_name} : {i}') + time.sleep(0.5) + def test_return(self): + return(f'{self.code_name}=END') +thread_name_list=["A","B","C","D"] +thread_list=[] +for i in range(0,len(thread_name_list)): + thread_list.append(Thread_class(thread_name_list[i])) +for i in range(0,len(thread_list)): + thread_list[i].start() # 啟動額外線程 +for i in range(0,len(thread_list)): + thread_list[i].join() + +``` + +``` +class Thread_class(threading.Thread): + def __init__(self,code_name): + threading.Thread.__init__(self) + self.code_name = code_name + + def run(self): + print('process {} '.format(os.getpid())) # 查看進程 + print('thread {} '.format(threading.current_thread().name)) # 查看線程 + for i in range(0,5): + print(f'{self.code_name} : {i}') + time.sleep(0.5) + def test_return(self): + return(f'{self.code_name}=END') +thread_name_list=["A","B","C","D"] +thread_list=[] +for i in range(0,len(thread_name_list)): + thread_list.append(Thread_class(thread_name_list[i])) +for i in range(0,len(thread_list)): + thread_list[i].run() # 這樣只會套用到 呼叫method,會用主線程去調用 +for i in range(0,len(thread_list)): + thread_list[i].join() +``` + +### Qthread: +* 使用方式與thread相似 +* 多了信號槽使用(可以擁有多個) +* 方便與主UI的線程溝通 +``` +class ReadTime(QtCore.QThread): # 讀取時間 + time_out = pyqtSignal(str) # 聲明一個帶字串參數的信號槽 + def __init__(self, parent=None): + super().__init__(parent) + def run(self): + while True: + result = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) # 讀取當下時間 + self.time_out.emit(f'{result}') # 傳送信号 + self.msleep(500) # 休眠0.5秒 +``` +## +## 多進程 +### 多進程與多線程的寫法極為相似 +#### 正常使用: +#### 2個進程幾乎同時啟動 +``` +# A報數 +def A_Count_off(): + for i in range(0,5): + print(f'A : {i}') + time.sleep(0.5) + + +# B報數 +def B_Count_off(): + for i in range(5,10): + print(f'B : {i}') + time.sleep(0.5) + + +if __name__=='__main__': + process_list=[A_Count_off,B_Count_off] + process_name =[] + for i in range(0,len(process_list)): + process_name.append(mp.Process(target=process_list[i])) + + for i in range(0,len(process_name)): + process_name[i].start() + + for i in range(0,len(process_name)): + process_name[i].join() +``` +### 非正常使用: +#### 第2個進程要等到第1個進程運行完才會啟動 +#### 失去多進程意義 + +``` +# A報數 +def A_Count_off(): + for i in range(0,5): + print(f'A : {i}') + time.sleep(0.5) + + +# B報數 +def B_Count_off(): + for i in range(5,10): + print(f'B : {i}') + time.sleep(0.5) + + +if __name__=='__main__': + process_list=[A_Count_off,B_Count_off] + process_name =[] + for i in range(0,len(process_list)): + process_name.append(mp.Process(target=process_list[i])) + + for i in range(0,len(process_name)): + process_name[i].start() + process_name[i].join() + + +``` + +### 攜帶參數 +``` +if __name__=='__main__': + process_name_list=["A","B","C","D"] + process_list=[] + for i in range(0,len(process_name_list)): + process_list.append(mp.Process(target=Count_off,args=process_name_list[i])) # 攜帶參數 +``` +### 使用class的方式(推薦使用) +#### 後續觀看程式碼及維護,會提高不少 +* start會使用分出去的進程 +* run會使用主線程 +* 但start後,無法直接調用此class的參數,等等會大概說明 +``` +class Process_class(mp.Process): + def __init__(self, code_name): + mp.Process.__init__(self) + self.code_name = code_name + + def run(self): + print('process {} '.format(os.getpid())) # 查看進程 + print('thread {} '.format(threading.current_thread().name)) # 查看線程 + for i in range(0,5): + print(f'{self.code_name} : {i}') + time.sleep(0.5) + def test_return(self): + return(f'{self.code_name}=END') + +if __name__=='__main__': + start_time = time.time() + process_name_list = ["A", "B", "C", "D"] + process_list = [] + for i in range(0, len(process_name_list)): + process_list.append(Process_class(process_name_list[i])) + for i in range(0, len(process_list)): + process_list[i].start() + for i in range(0, len(process_list)): + process_list[i].join() + + for i in range(0, len(process_list)): + print(process_list[i].test_return()) +``` +### 多進程的溝通方式 +#### 多進程的溝通方式需要透過Queue或pipe + 參考資料 + http://www.taroballz.com/2018/01/11/processing_communcation/ + 多線程由於共享記憶體溝通方式比多進程方便 + 2者差異的參考資料 + https://blog.csdn.net/Victor2code/article/details/109005171 +#### 用團隊合作方式來理解,每個人都在做自己的事,若沒有溝通或是告知(Queue),則沒有辦法獲取資料 + + +