.. | ||
code | ||
python_thread.pptx | ||
README.md |
多工
用到多工場合:
- 同時間須顯示許多資料
- 讀取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