進程

由於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.")

運行截圖如下:

運行結果

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


推薦閱讀:
相关文章