一.os模塊中的fork方法(只在linux系統中使用,Windows系統不可用)
Python在os模塊上封裝了常用的系統調用,其中就包括了fork,我們可以很輕鬆地在Python代碼中創建進程。
import os, time def sing(): for x in range(5): print("在唱歌") time.sleep(1) def network(): for x in range(5): print("在上網") time.sleep(1) # 注意:os模塊下的fork()方法在Windows系統中無法使用,只能在Linux系統中使用,比如 Ubuntu 15.04 res = os.fork() if res == 0: sing() else: network() print("這個程序會執行兩次")
Python中的fork() 函數可以獲得系統中進程的PID ( Process ID ),返回0則爲子進程,否則就是父進程,然後可以據此對運行中的進程進行操作;
但是強大的 fork() 函數在Windows版的Python中是無法使用的。。。只能在Linux系統中使用,比如 Ubuntu 15.04,Windows中獲取父進程ID可以用 getpid()。
os.getpid()、os.getppid()(獲得當前進程編號、獲得父進程編號)
我們可以使用os模塊的getpid來獲取當前進程的進程編號,同樣也可以使用os.getppid()方法案來獲取當前進程的父進程編號。
import os import time # 使用os模塊的fork方法可以創建一個新的進程 pid = os.fork() if pid == 0: while True: print("我是子線程,我的編號是%s,我的父進程編號是%s" %(os.getpid(),os.getppid())) time.sleep(1) else: while True: print("我是父線程,我的編號是%s,我的子進程編號是%s" %(os.getpid(), pid)) time.sleep(1) |
使用os模塊中的getpid()方法,可以得到當前線程的編號,使用getppid()方法可以得到該線程的父級編號。
二、multiprocessing模塊下的Process類實現多進程(通用)
前面我們使用os.fork()方法實現了多進程,但是這種方案只能在Linux下運行,window環境下是無法運行的,那麼有沒有可以實現在任何平臺都能運行的多進程了,有!Python爲大家提供了multiprocessing模塊用來實現多進程。
(1)函數實現方式
# 1.函數實現多進程——無參版 from multiprocessing import Process def run(): print("這是一個子進程") if __name__ == '__main__': print("++++++++++++ main start +++++++++++++") t1 = Process(target=run) t1.start() print("============ main end =============") ''' 運行結果: ++++++++++++ main start +++++++++++++ ============ main end ============= 這是一個子進程 ''' # 2.函數實現多進程——有參版 from multiprocessing import Process def run1(msg): print("這是一個有參數的子進程,參數爲: %s"%msg) if __name__ == '__main__': print("++++++++++++ main start +++++++++++++") t1 = Process(target=run1,args=("嘿嘿",)) # args爲調用的子進程的函數的參數,注意類型是一個元組或者列表。
t1.start()
print("============ main end =============") ''' 運行結果爲: ++++++++++++ main start +++++++++++++ ============ main end ============= 這是一個有參數的子進程,參數爲: 嘿嘿 ''' # 3.多個進程同一函數運行先後順序,順序無法確定 from multiprocessing import Process import time def run2(msg): for x in range(3): print("這是一個有參數的子進程,參數爲: %s"%msg) time.sleep(1) # 人爲的讓代碼停頓,是其他進程有機會搶入 if __name__ == '__main__': print("++++++++++++ main start +++++++++++++") t1 = Process(target=run2,args=("嘿嘿",)) t1.start() t2 = Process(target=run2, args=("哈哈",)) t2.start() t3 = Process(target=run2, args=("呵呵",)) t3.start() print("============ main end =============") '''運行結果: ++++++++++++ main start +++++++++++++ ============ main end ============= 這是一個有參數的子進程,參數爲: 哈哈 這是一個有參數的子進程,參數爲: 嘿嘿 這是一個有參數的子進程,參數爲: 呵呵 這是一個有參數的子進程,參數爲: 哈哈 這是一個有參數的子進程,參數爲: 嘿嘿 這是一個有參數的子進程,參數爲: 呵呵 這是一個有參數的子進程,參數爲: 嘿嘿 這是一個有參數的子進程,參數爲: 哈哈 這是一個有參數的子進程,參數爲: 呵呵 ''' # 4.多函數多進程,順序依然無法確定 from multiprocessing import Process import time def run3(msg): for x in range(3): print("這是第一個有參數的子進程,參數爲: %s111"%msg) time.sleep(1) # 人爲的讓代碼停頓,是其他進程有機會搶入 def run4(msg): for x in range(3): print("這是第二個有參數的子進程,參數爲: %s222" % msg) time.sleep(1) def run5(msg): for x in range(3): print("這是第三個有參數的子進程,參數爲: %s333" % msg) time.sleep(1) if __name__ == '__main__': print("++++++++++++ main start +++++++++++++") t1 = Process(target=run3,args=("嘿嘿",)) t1.start() t2 = Process(target=run4, args=("哈哈",)) t2.start() t3 = Process(target=run5, args=("呵呵",)) t3.start() print("============ main end =============") ''' 運行結果: ++++++++++++ main start +++++++++++++ ============ main end ============= 這是第二個有參數的子進程,參數爲: 哈哈222 這是第一個有參數的子進程,參數爲: 嘿嘿111 這是第三個有參數的子進程,參數爲: 呵呵333 這是第一個有參數的子進程,參數爲: 嘿嘿111 這是第二個有參數的子進程,參數爲: 哈哈222 這是第三個有參數的子進程,參數爲: 呵呵333 這是第一個有參數的子進程,參數爲: 嘿嘿111 這是第二個有參數的子進程,參數爲: 哈哈222 這是第三個有參數的子進程,參數爲: 呵呵333 ''' # 5.讓主進程等待子進程 from multiprocessing import Process def run1(msg): print("這是一個有參數的子進程,參數爲: %s"%msg) if __name__ == '__main__': print("++++++++++++ main start +++++++++++++") t1 = Process(target=run1,args=("嘿嘿",)) t1.start() t1.join() # join方法表示只有子進程執行完成後,主進程才能結束。主進程會等待子進程完成後,自身才會執行完成。 print("============ main end =============") ''' 運行結果爲: ++++++++++++ main start +++++++++++++ 這是一個有參數的子進程,參數爲: 嘿嘿 ============ main end ============= ''' (2)類實現方式# 1.無參數型,定義一個類,使其繼承自Process類,重寫run方法即可 from multiprocessing import Process class MyProcess(Process): def run(self): print("這是類實現的子進程") if __name__ == '__main__': print("++++++++++++ main start +++++++++++++") myprocess = MyProcess() myprocess.start() print("============ main end ================") ''' 運行結果: ++++++++++++ main start +++++++++++++ ============ main end ================ 這是類實現的子進程 ''' # 2.有參數型 from multiprocessing import Process class MyProcess(Process): def __init__(self,name,msg): super().__init__(name=name) self.msg = msg def run(self): print("這是類實現的子進程") print(self.name) print(self.msg) if __name__ == '__main__': print("++++++++++++ main start +++++++++++++") myprocess = MyProcess("子進程名稱","參數內容") myprocess.start() print("============ main end ================") ''' 運行結果: ++++++++++++ main start +++++++++++++ ============ main end ================ 這是類實現的子進程 子進程名稱 參數內容 '''三、進程池Pool
from multiprocessing import Pool def run(): print("這是一個子進程") return 0 def run1(): print("這是另一個子進程") return 1 def cb(msg): print("這是一個回調函數,回調函數的參數來自子進程的返回值,返回值爲%s"%msg) if __name__ == '__main__': print("+++++++++++ main start +++++++++++") pool = Pool(3) # 可以設定提前創建的子進程的數目,一般根據項目需求確定 for x in range(3): pool.apply_async(func=run,callback=cb) # callback爲回調函數,子進程結束後纔會執行 pool.apply_async(func=run1, callback=cb) pool.close() # 一定要先關閉,後join() pool.join() print("=========== main end ============") ''' 運行結果: +++++++++++ main start +++++++++++ 這是一個子進程 這是另一個子進程 這是一個回調函數,回調函數的參數來自子進程的返回值,返回值爲0 這是一個子進程 這是一個回調函數,回調函數的參數來自子進程的返回值,返回值爲1 這是一個回調函數,回調函數的參數來自子進程的返回值,返回值爲0 這是另一個子進程 這是一個回調函數,回調函數的參數來自子進程的返回值,返回值爲1 這是一個子進程 這是一個回調函數,回調函數的參數來自子進程的返回值,返回值爲0 這是另一個子進程 這是一個回調函數,回調函數的參數來自子進程的返回值,返回值爲1 =========== main end ============ '''
注意:一般我們使用apply_async這個方法,表示非阻塞的運行,一旦使用了apply方法表示阻塞式執行任務,此時就是單任務執行了(一般不會使用,特殊場景纔會使用)
四、消息隊列Queue\Pipe管道\manager實現進程間的通訊(進程間原本無法通訊,即便是全局變量也是各自使用,不會共享)(1)消息隊列Queue
我們可以使用multiprocessing模塊中的Queue(消息隊列)來完成多進程間的數據傳遞
我們可以通過queue獲取隊列對象,隊列對象的常用方法如下:
q.put() q.get() q.get(item,block=True,timeout=None) q.put(item,block=True,timeout=None) q.empty() q.full() q.qsize() q.put_nowait() q.get_nowait() |
from multiprocessing import Process, Pool, Queue # Queue隊列的特徵:先進先出,注意queue是線程的隊列,不同於Queue import time def sendMsg(q,msg): while True: print("發送數據:%s>>>>>>>>>>>>>>>>>>>>>>" % msg) q.put(msg) time.sleep(1) def accept(q): while True: print("<<<<<<<<<<<<<<<<<<<<<接收到的數據爲:%s"%q.get()) time.sleep(1) if __name__ == '__main__': q = Queue(5) # 表示最多可以推進消息的數量 new_time = time.time() print("++++++++++++++++++ main start +++++++++++++++++++++") t1 = Process(target=sendMsg, args=(q,"你好嗎?"), name="發送數據進程") t1.start() t2 = Process(target=accept,args=(q,), name="接收數據進程") t2.start() print("================== main end ======================", time.time() - new_time)
''' 運行結果: ++++++++++++++++++ main start +++++++++++++++++++++ ================== main end ====================== 0.03002023696899414 發送數據:你好嗎?>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<接收到的數據爲:你好嗎? 發送數據:你好嗎?>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<接收到的數據爲:你好嗎? 發送數據:你好嗎?>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<接收到的數據爲:你好嗎? '''(2)Pipe管道
from multiprocessing import Process,Pipe import time def sendMsg(p,msg): print("發送數據:%s>>>>>>>>>>>>>>>>>>>>>>" % msg) p.send(msg) p.close() time.sleep(1) if __name__ == '__main__': p1,p2 = Pipe() # Pipe管道返回值有兩個,一個是父進程,一個是子進程 print(p1,p2) # 可以將p1,p2打印出來看看 new_time = time.time() print("++++++++++++++++++ main start +++++++++++++++++++++") t1 = Process(target=sendMsg, args=(p1,"你好嗎?"), name="發送數據進程") t1.start() print("<<<<<<<<<<<<<<<接收到的數據爲:%s"%p2.recv()) print("================== main end ======================", time.time() - new_time) ''' 運行結果: <multiprocessing.connection.PipeConnection object at 0x0000023B3CDC1F28> <multiprocessing.connection.PipeConnection object at 0x0000023B3CBE72B0> ++++++++++++++++++ main start +++++++++++++++++++++ 發送數據:你好嗎?>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<接收到的數據爲:你好嗎? ================== main end ====================== 0.2751955986022949 '''(3)manager
之前我們學習進程間的數據通信僅僅只是數據的傳遞,而不是數據的共享,那麼如果我們想實現進程間的數據共享應該怎麼做呢?使用Manager來實現。
Managers支持的數據類型有list、dict、Namespace、Lock、Rlock、Queue、Value、Array and so on。
from multiprocessing import Process, Manager def saveDatas(lists, dicts): lists.append("武松") lists.append("潘金蓮") lists.append("武大郎") dicts["name"] = "姜子牙" dicts["age"] = 80 dicts["mp"] = 50 print(lists) print(dicts) if __name__ == '__main__': print("++++++++++++++ main start +++++++++++++++++++") # manager = Manager() # 獲取一個Manager對象 with Manager() as manager: # <==>manager = Manager() lists = manager.list() # 普通的list無法跨越多進程,只有manager中的list可以 dicts = manager.dict() ls = [] # 啓動線程 for x in range(5): task = Process(target=saveDatas, args=(lists, dicts)) task.start() ls.append(task) # 如果join()方法寫在這裏,則是一個進程結束後纔開始第二個進程,進程之間數據同步,類似於單進程 # for i in ls: i.join() # manager 也要藉助於join()方法來迫使主進程等待子進程的運行 print("================ main end ================") ''' 運行結果:++++++++++++++ main start +++++++++++++++++++ ['武松', '潘金蓮', '武大郎'] {'age': 80, 'mp': 50, 'name': '姜子牙'} ['武松', '潘金蓮', '武大郎', '武松', '潘金蓮', '武大郎'] {'age': 80, 'mp': 50, 'name': '姜子牙'} ['武松', '潘金蓮', '武大郎', '武松', '潘金蓮', '武大郎', '武松', '潘金蓮', '武大郎'] {'age': 80, 'mp': 50, 'name': '姜子牙'} ['武松', '潘金蓮', '武大郎', '武松', '潘金蓮', '武大郎', '武松', '潘金蓮', '武大郎', '武松', '潘金蓮', '武大郎'] {'age': 80, 'mp': 50, 'name': '姜子牙'} ['武松', '潘金蓮', '武大郎', '武松', '潘金蓮', '武大郎', '武松', '潘金蓮', '武大郎', '武松', '潘金蓮', '武大郎', '武松', '潘金蓮', '武大郎'] {'age': 80, 'mp': 50, 'name': '姜子牙'} ================ main end ================ '''