程式
由於GIL
的存在,Python中的多執行緒其實並不是真正的多執行緒,如果想要充分地使用多核CPU
的資源,在Python中大部分情況需要使用多程式。Python提供了非常好用的多程式模組multiprocessing
,只需要定義一個函式,Python會完成其他所有事情。藉助這個模組,可以輕鬆完成從單程式到併發執行的轉換。multiprocessing
支援子程式、通訊和共享資料、執行不同形式的同步,提供了Process
、Lock
、Queue
、Pipe
等元件。
multiprocessing
模組是Python中的多程式模組。與threading.Thread
類似,它可以利用multiprocessing.Process
物件來建立一個程式。該程式可以執行在Python程式內部編寫的函式。該Process物件與Thread物件的用法相同,也有start()
,run(),
join()
的方法。此外multiprocessing
模組中也有Lock
/Event
/Semaphore
/Condition
類 (這些物件可以像多執行緒那樣,通過引數傳遞給各個程式),用以同步程式,其用法與threading
模組中的同名類一致。所以,multiprocessing
的很大一部份與threading
使用同一套API,只不過換到了多程式的情境。
當然多程式的定義方式也和多執行緒類似,即兩種方式:
目標函式例項化定義新的程式:
# 匯入多程式模組
from multiprocessing import Process
# os.getpid() 獲取當前程式的id
import os
def run_proc(name):
print('{} child process is {}'.format(name, os.getpid()))
if __name__ == '__main__':
print("Parent process is {}".format(os.getpid()))
p = Process(target=run_proc, args=('test', ))
print('child process will start...')
p.start()
p.join()
print('child process end.')
複製程式碼
執行截圖如下:
繼承類來定義新的程式
from multiprocessing import Process
import os
class RunProc(Process):
def __init__(self, name):
Process.__init__(self)
self.name = name
def run(self):
print('{} child process is {}'.format(self.name, os.getpid()))
if __name__ == "__main__":
print("Parent process is {}".format(os.getpid()))
p = RunProc('test')
print('child process will start...')
p.start()
p.join()
print('child process end.')
複製程式碼
執行結果如下:
我們可以看見,多程式的使用方式和多執行緒幾乎一樣,比如以下: Process([group [, target [, name [, args [, kwargs]]]]])- group: 執行緒組,目前還沒有實現,庫引用中提示必須是None;
- target: 要執行的方法;
- name: 程式名;
- args/kwargs: 要傳入方法的引數。
例項方法:
- is_alive():返回程式是否在執行。
- join([timeout]):阻塞當前上下文環境的程式程,直到呼叫此方法的程式終止或到達指定的timeout(可選引數)。
- start():程式準備就緒,等待CPU排程
- run():strat()呼叫run方法,如果例項程式時未制定傳入
target
,start
執行預設的·run()
方法。 - terminate():不管任務是否完成,立即停止工作程式
屬性:
- daemon:和執行緒的
setDeamon
功能一樣 - exitcode(程式在執行時為None、如果為–N,表示被訊號N結束)
- name:程式名字。
- pid:程式號。
程式的獨立性:
和執行緒不一樣的是,程式之間相互獨立,我們可以從全域性變數的修改窺見一些:
from multiprocessing import Process
# 測試資料
ex_list = 'Hello World'
# 修改資料程式
def revise_data():
global ex_list
# 修改全域性變數
ex_list = ex_list + ' with write revise_data process.'
print('wirte result:', ex_list)
# 檢視資料程式
def view_data():
print(ex_list)
if __name__ == "__main__":
process_revise = Process(target=revise_data)
process_view = Process(target=view_data)
process_revise.start()
# 主程式等待寫入程式執行完成以後程式碼 再繼續往下執行
process_revise.join()
process_view.start()
process_view.join()
print("process end.")
複製程式碼
執行截圖如下:
我們定義了兩個程式,分別用來修改全域性變數和檢視修改後的資料,我們看見雖然修改的程式已經成功修改了變數,但是在檢視程式中全域性變數仍然是原來的值,即程式之間是不共享全域性變數的,即建立子程式其實是對主程式進行拷貝,程式之間相互獨立,訪問的全域性變數不是同一個,所以程式之間不共享全域性變數。