Python多程式之Process、Pool、Lock、Queue、Event、Semaphore、Pipe
1. Python建立程式類Process
python的multiprocessing模組提供了一個建立程式的類Precess,其建立有以下兩種方法:
建立Process類的例項,並指向目標函式和傳遞引數
自定義一個類並繼承Process類,重寫__init__()和run()方法
Process類的建構函式如下:
class multiprocessing.Process(group, target, name, kwargs)
def __init__(self,
group: Any = ...,
target: Optional[Callable] = ...,
name: Optional[str] = ...,
args: Iterable[Any] = ...,
kwargs: Mapping[Any, Any] = ...,
*,
daemon: Optional[bool] = ...) -> None: ...
引數說明:
target 表示呼叫物件,一般為任務函式,也可以為類;
args 給呼叫物件target傳遞的引數,為元組
kwargs 表示呼叫物件的字典
name 為程式的別名
group 引數不使用,可以忽略
Process類常用的方法和屬性如下
方法
is_alive(): 返回程式是否啟用
join([timeout]): 阻塞程式,直到程式執行完成或超時或程式被終止
run(): 代表程式執行任務的函式,可被重寫
start(): 啟用啟動程式
terminate(): 終止程式
屬性
authkey(): 位元組碼,程式的準秘鑰
daemon(): 為True時,父程式終止後所有子程式自動終止,且不能產生新的程式,必須在start()方法前設定
exitcode:退出碼,程式在執行時為None,如果為-N,就表示被訊號N結束
name:獲取程式名稱
pid:程式id
1.1 我們首先使用第一種方法建立兩個程式,並與單程式執行的時間做比較
from multiprocessing import Process
import time
def task_process(delay):
num = 0
for i in range(delay * 100000000): # 1億次資料累加計算
num += i
if __name__ == '__main__':
t0 = time.time()
task_process(3)
task_process(3)
t1 = time.time()
print(f"單程式順序執行耗時 {t1 - t0} ")
p0 = Process(target=task_process, args=(3,))
p1 = Process(target=task_process, args=(3,))
t2 = time.time()
p0.start()
p1.start()
p0.join()
p1.join()
t3 = time.time()
print(f"多程式併發執行耗時 {t3 - t2}")
輸出結果:多程式執行相同的操作消耗的時間更少!
單程式順序執行耗時 32.359516859054565
多程式併發執行耗時 17.804959535598755
1.2 使用第二種方法,自定義一個類並繼承Process類
from multiprocessing import Process
import time
class MyProcess(Process):
def __init__(self, delay):
super().__init__()
self.delay = delay
# 子程式要執行的程式碼
def run(self):
num = 0
for i in range(self.delay * 100000000):
num += i
if __name__ == "__main__":
p0 = MyProcess(3)
p1 = MyProcess(3)
t0 = time.time()
p0.start()
p1.start()
p0.join()
p1.join()
t1 = time.time()
print(f"多程式併發執行耗時 {t1 - t0}")
輸出結果
多程式併發執行耗時 16.68904447555542
2. 程式池Pool
程式池Pool可以提供指定數量的程式給使用者使用,當有新的請求程式時,若Pool池沒有滿,就會建立一個新的程式用於執行該請求,如果Pool池中的程式數量已經達到最大值,則請求會等待,直到池中有程式結束才會建立新的程式。
示例:
# coding: utf-8
import multiprocessing
import time
def task(name):
print(f"{time.strftime('%H:%M:%S')}: {name} 開始執行")
time.sleep(3)
if __name__ == "__main__":
pool = multiprocessing.Pool(processes=3)
for i in range(10):
# 維持執行的程式總數為processes,當一個程式執行完畢後會新增新的程式進去
pool.apply_async(func=task, args=(i,))
pool.close()
pool.join()
print("hello")
輸出:
19:43:22: 0 開始執行
19:43:22: 1 開始執行
19:43:22: 2 開始執行
19:43:25: 3 開始執行
19:43:25: 4 開始執行
19:43:25: 5 開始執行
19:43:28: 6 開始執行
19:43:28: 7 開始執行
19:43:28: 8 開始執行
19:43:31: 9 開始執行
hello
3.同步機制之Lock鎖
多程式的目的是併發執行程式,提高程式執行效率,但有時候我們想要在某一時間,或者滿足某一條件時,只有一個程式在執行,就需要使用Lock鎖機制。
示例:
import multiprocessing
import time
def task1(lock):
with lock: # with上下文語句使用鎖,會自動釋放鎖
n = 5
while n > 1:
print(f"{time.strftime('%H:%M:%S')} task1 輸出資訊")
time.sleep(1)
n -= 1
def task2(lock):
lock.acquire()
n = 5
while n > 1:
print(f"{time.strftime('%H:%M:%S')} task2 輸出資訊")
time.sleep(1)
n -= 1
lock.release()
def task3(lock):
lock.acquire()
n = 5
while n > 1:
print(f"{time.strftime('%H:%M:%S')} task3 輸出資訊")
time.sleep(1)
n -= 1
lock.release()
if __name__ == "__main__":
lock = multiprocessing.Lock()
p1 = multiprocessing.Process(target=task1, args=(lock,))
p2 = multiprocessing.Process(target=task2, args=(lock,))
p3 = multiprocessing.Process(target=task3, args=(lock,))
p1.start()
p2.start()
p3.start()
輸出:
20:13:22 task1 輸出資訊
20:13:23 task1 輸出資訊
20:13:24 task1 輸出資訊
20:13:25 task1 輸出資訊
20:13:26 task2 輸出資訊
20:13:27 task2 輸出資訊
20:13:28 task2 輸出資訊
20:13:29 task2 輸出資訊
20:13:30 task3 輸出資訊
20:13:31 task3 輸出資訊
20:13:32 task3 輸出資訊
20:13:33 task3 輸出資訊
說明:從結果上看,由於鎖的機制,同一時刻只有一個程式在執行。
使用lock = multiprocess.Lock()可以得到一個鎖的例項,在上面的程式碼中,可以使用with語句來使用鎖,也可以在要執行的程式碼塊前使用lock.acquire()方法,在執行完後再釋放lock.release()鎖,需要注意的是lock.acquire()後面的語句不能阻塞,否則會發生死鎖的情況
4.程式佇列Queue
Queue是python多程式的安全佇列,可以使用Queue實現多程式之間的資料傳遞。
Queue.put()方法說明:
Queue.put(self, obj, block=True, timeout=None) # 用於插入資料到佇列中
當block為True,timeout為正值時,該方法會阻塞timeout指定的時間,直到該佇列有剩餘的空閒時間。如果超時,會丟擲Queue.Full異常
當block為False,但佇列已滿,會丟擲Queue.Full異常
Queue.get()方法說明:
Queue.get(self, block=True, timeout=None) # 從佇列中取出資料並刪除
當block為True,timeout為正值時,在timeout時間內沒用取到資料就會丟擲Queue.Empty異常
當block為False時,有兩種情況:若佇列中有資料則取出;若佇列為空則丟擲Queue.Empty異常。
示例:
from multiprocessing import Process, Queue
import time
def ProducerA(q):
count = 1
while True:
q.put(f"冷飲 {count}")
print(f"{time.strftime('%H:%M:%S')} A 放入:[冷飲 {count}]")
count += 1
time.sleep(1)
def ConsumerB(q):
while True:
print(f"{time.strftime('%H:%M:%S')} B 取出 [{q.get()}]")
time.sleep(5)
if __name__ == '__main__':
q = Queue(maxsize=5)
p = Process(target=ProducerA, args=(q,))
c = Process(target=ConsumerB, args=(q,))
c.start()
p.start()
c.join()
p.join()
輸出:
19:07:09 A 放入:[冷飲 1]
19:07:09 B 取出 [冷飲 1]
19:07:10 A 放入:[冷飲 2]
19:07:11 A 放入:[冷飲 3]
19:07:12 A 放入:[冷飲 4]
19:07:13 A 放入:[冷飲 5]
19:07:14 B 取出 [冷飲 2]
19:07:14 A 放入:[冷飲 6]
19:07:15 A 放入:[冷飲 7]
19:07:19 B 取出 [冷飲 3]
19:07:19 A 放入:[冷飲 8]
19:07:24 B 取出 [冷飲 4]
19:07:24 A 放入:[冷飲 9]
19:07:29 B 取出 [冷飲 5]
19:07:29 A 放入:[冷飲 10]
說明:上述程式碼定義了生產者和消費者函式,設定佇列最大容量為5,生產者呼叫Queue.put()方法放入資料,消費呼叫Queue.get()方法取出資料,當佇列滿時,生產者等待,當佇列空時,消費者等待。生產的速度和消費的速度可能不一致,但是佇列能讓生產和消費有條不紊地進行。
5.同步機制Event
Event用來實現多程式之間的同步通訊
示例:
import multiprocessing
import time
def wait_for_event(e):
e.wait()
time.sleep(1)
# 喚醒後清除Event狀態,為後續繼續等待
e.clear()
print(f"{time.strftime('%H:%M:%S')} 程式 A: 我們是兄弟,我等你...")
e.wait()
print(f"{time.strftime('%H:%M:%S')} 程式 A: 好的,是兄弟一起走")
def wait_for_event_timeout(e, t):
e.wait()
time.sleep(1)
# 喚醒後清除Event狀態,為後續繼續等待
e.clear()
print(f"{time.strftime('%H:%M:%S')} 程式 B: 好吧,最多等你 {t} 秒")
e.wait(t)
print(f"{time.strftime('%H:%M:%S')} 程式 B: 我繼續往前走了")
if __name__ == "__main__":
e = multiprocessing.Event()
w1 = multiprocessing.Process(target=wait_for_event, args=(e,))
w2 = multiprocessing.Process(target=wait_for_event_timeout, args=(e, 5))
w1.start()
w2.start()
# 主程式發話
print(f"{time.strftime('%H:%M:%S')} 主程式: 誰等我下,我需要 8 s 時間")
# 喚醒等待的程式
e.set()
time.sleep(8)
print(f"{time.strftime('%H:%M:%S')} 主程式: 好了,我趕上了")
# 再次喚醒等待的程式
e.set()
w1.join()
w2.join()
print(f"{time.strftime('%H:%M:%S')} 主程式:退出")
輸出:
20:28:25 主程式: 誰等我下,我需要 8 s 時間
20:28:26 程式 A: 我們是兄弟,我等你...
20:28:26 程式 B: 好吧,最多等你 5 秒
20:28:31 程式 B: 我繼續往前走了
20:28:33 主程式: 好了,我趕上了
20:28:33 程式 A: 好的,是兄弟一起走
20:28:33 主程式:退出
說明:上述程式碼定義了兩個程式函式,一個是等待事件發生,一個是設定超時時間後等待事件發生,主程式呼叫事件的set()方法喚醒等待事件的程式,事件被喚醒後呼叫clear()方法清除事件的狀態並呼叫wait()重新等待,以此達到程式同步的控制。
6.併發控制之Semaphore
Semaphore是用來控制對共享資源的訪問量,可以控制同一時刻程式的併發數量。
示例:
import multiprocessing
import time
def worker(s, i):
s.acquire() # 獲得鎖
print(time.strftime('%H:%M:%S'), multiprocessing.current_process().name + " 獲得鎖執行");
time.sleep(i)
print(time.strftime('%H:%M:%S'), multiprocessing.current_process().name + " 釋放鎖結束");
s.release() # 釋放鎖
if __name__ == "__main__":
s = multiprocessing.Semaphore(2)
for i in range(6):
p = multiprocessing.Process(target=worker, args=(s, 2))
p.start()
輸出: 山東棗莊東方婦科醫院
20:07:17 Process-1 獲得鎖執行
20:07:17 Process-2 獲得鎖執行
20:07:19 Process-1 釋放鎖結束
20:07:19 Process-3 獲得鎖執行
20:07:19 Process-2 釋放鎖結束
20:07:19 Process-4 獲得鎖執行
20:07:21 Process-3 釋放鎖結束
20:07:21 Process-5 獲得鎖執行
20:07:21 Process-4 釋放鎖結束
20:07:21 Process-6 獲得鎖執行
20:07:23 Process-5 釋放鎖結束
20:07:23 Process-6 釋放鎖結束
說明:multiprocessing.Semaphore(2)定義了同一時刻只能有2個程式在執行
7.程式間資料傳遞Pipe
multiprocessing.Pipe()方法會返回一個管道(列表的形式)的兩個埠,一個埠作為輸入端,一個埠作為輸出端,如程式A的輸出可以作為程式B的輸入,程式B的輸出可以作為程式A的輸入,預設是全雙工模式。
Pipe()方法返回的物件具有傳送訊息send()方法和接收訊息recv()方法。呼叫接收recv()方法時,如果管道中沒用訊息會一直阻塞,如果管道關閉,則會丟擲EOFError異常。
示例:
import multiprocessing
import time
def task1(pipe):
for i in range(5):
str = f"task1-{i}"
print(f"{time.strftime('%H:%M:%S')} task1 傳送:{str}")
pipe.send(str)
time.sleep(2)
for i in range(5):
print(f"{time.strftime('%H:%M:%S')} task1 接收: { pipe.recv() }")
def task2(pipe):
for i in range(5):
print(f"{time.strftime('%H:%M:%S')} task2 接收: { pipe.recv() }")
time.sleep(1)
for i in range(5):
str = f"task2-{i}"
print(f"{time.strftime('%H:%M:%S')} task2 傳送:{str}")
pipe.send(str)
if __name__ == "__main__":
pipe = multiprocessing.Pipe()
p1 = multiprocessing.Process(target=task1, args=(pipe[0],)) # pipe[0]管道傳送訊息的埠
p2 = multiprocessing.Process(target=task2, args=(pipe[1],)) # pipe[1]管道接收訊息的埠
p1.start()
p2.start()
p1.join()
p2.join()
輸出:
17:23:53 task1 傳送:task1-0
17:23:53 task1 傳送:task1-1
17:23:53 task1 傳送:task1-2
17:23:53 task1 傳送:task1-3
17:23:53 task1 傳送:task1-4
17:23:53 task2 接收: task1-0
17:23:53 task2 接收: task1-1
17:23:53 task2 接收: task1-2
17:23:53 task2 接收: task1-3
17:23:53 task2 接收: task1-4
17:23:54 task2 傳送:task2-0
17:23:54 task2 傳送:task2-1
17:23:54 task2 傳送:task2-2
17:23:54 task2 傳送:task2-3
17:23:54 task2 傳送:task2-4
17:23:55 task1 接收: task2-0
17:23:55 task1 接收: task2-1
17:23:55 task1 接收: task2-2
17:23:55 task1 接收: task2-3
17:23:55 task1 接收: task2-4
說明:定義了兩個任務函式,task1先發5條訊息,再接收訊息,task2先接收訊息,再傳送訊息。呼叫time.sleep()只是讓輸出更好看點,不會影響管道的接收和傳送。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69945560/viewspace-2760926/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Python多程式之資料交換PipePython
- pipe stderr into another process
- 從promise、process.nextTick、setTimeout出發,談談Event Loop中的Job queuePromiseOOP
- 淺談synchronized、Lock、ThreadLocal和semaphoresynchronizedthread
- Python程式專題4:程式池PoolPython
- Python並行程式設計(九):多程式物件交換之pipe(管道)實現生產者-消費者模型Python並行行程程式設計物件模型
- Java多執行緒同步工具類之SemaphoreJava執行緒
- [Python] pipe模組Python
- 併發程式設計之:Lock程式設計
- Swoole 中通過 process 模組實現多程式
- python佇列QueuePython佇列
- Python並行程式設計(六):多執行緒同步之queue(佇列)實現生產者-消費者模型Python並行行程程式設計執行緒佇列模型
- [轉載] Python程式——multiprocessing.Event()|Barrier()Python
- (十五) 學習筆記: Python程式(Process)相關筆記Python
- Java併發程式設計系列之Semaphore詳解Java程式設計
- 對於Pipe管道之愛 - jessfraz
- Python中如何清空Queue?Python
- Python並行程式設計(三):多執行緒同步之semaphore(訊號量)實現簡易生產者-消費者模型Python並行行程程式設計執行緒模型
- libevent之event
- Python多程式Python
- 豬行天下之Python基礎——9.1 Python多執行緒與多程式(上)Python執行緒
- 豬行天下之Python基礎——9.2 Python多執行緒與多程式(中)Python執行緒
- 豬行天下之Python基礎——9.3 Python多執行緒與多程式(下)Python執行緒
- python:python的多程式Python
- JUC併發程式設計之Semaphore、CountDownLatch、CyclicBarrier協同工具程式設計CountDownLatch
- 【Oracle】簡單引數也有講究,JOB_QUEUE_PROCESS引數調研Oracle
- Java併發程式設計之鎖機制之Lock介面Java程式設計
- mysql innodb lock鎖之record lock之一MySql
- Python學習筆記 - queuePython筆記
- Queue是python哪個庫?Python
- Java多執行緒之執行緒同步【synchronized、Lock、volatitle】Java執行緒synchronized
- python多執行緒+生產者和消費者模型+queue使用Python執行緒模型
- 2.Python程式間的通訊之佇列(Queue)和生產者消費者模型Python佇列模型
- 高併發之Semaphore、Exchanger、LockSupport
- Python並行程式設計(五):多執行緒同步之event(事件)實現簡易的生產者-消費者模型Python並行行程程式設計執行緒事件模型
- linux程式間通訊--管道(PIPE & FIFO)Linux
- java多執行緒系列:Semaphore和ExchangerJava執行緒
- Javascript之Event LoopJavaScriptOOP