Python並行程式設計(七):多程式的基本使用和與多執行緒的差異

若數發表於2019-04-14

程式

 由於GIL的存在,Python中的多執行緒其實並不是真正的多執行緒,如果想要充分地使用多核CPU的資源,在Python中大部分情況需要使用多程式。Python提供了非常好用的多程式模組multiprocessing,只需要定義一個函式,Python會完成其他所有事情。藉助這個模組,可以輕鬆完成從單程式到併發執行的轉換。multiprocessing支援子程式、通訊和共享資料、執行不同形式的同步,提供了ProcessLockQueuePipe等元件。

  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方法,如果例項程式時未制定傳入targetstart執行預設的· 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.")
複製程式碼

執行截圖如下:

執行結果
我們定義了兩個程式,分別用來修改全域性變數和檢視修改後的資料,我們看見雖然修改的程式已經成功修改了變數,但是在檢視程式中全域性變數仍然是原來的值,即程式之間是不共享全域性變數的,即建立子程式其實是對主程式進行拷貝,程式之間相互獨立,訪問的全域性變數不是同一個,所以程式之間不共享全域性變數。

相關文章