新增thread readme
This commit is contained in:
parent
a47075e5f0
commit
1a9cda80ff
282
Thread/README.md
282
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),則沒有辦法獲取資料
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user