進程是正在執行中的應用程序,一個進程包含了該應用程序的全部信息,如加載數據內存空
間、代碼、程序數據、對象句柄,執行單元等等,一個應用程序根據其功能的多樣性,能夠
經過多個進程併發的形式來實現。
計算機中多線程的操做已經能夠實現多任務的處理機制了,可是若是涉及到多核 CPU 或者
多個 CPU 的硬件主機,多進程併發編程的實現能比多線程併發機制更加有效的利用和發揮
硬件資源優點。python
名稱 | 描述 |
---|---|
Process | 進程類型,用於建立和管理進程 |
Lock | RLock |
Event | 進程事件類型,用於進程同步 |
Condition | 進程條件類型,用於進程同步 |
Queue | 進程隊列類型,用於多進程數據共享 |
Manager | 進程管理類型,用於多進程數據共享 |
Listener | Client |
import multiprocessing, time, os def hello_process(): # 打印信息,展現當前進程編號,父進程編號 print("hello my name is process", os.getpid(),os.getppid()) if __name__ == "__main__": # 建立一個進程 proc = multiprocessing.Process(target=hello_process) proc.start() print("hello, i am main:", os.getpid(), os.getppid())
運行程序,查看運行結果
hello ,i am :2456 2772
hello my name is process 13536 2456編程
多進程的面向對象的實現方式相似多線程的操做模式
自定義進程類型,繼承系統進程標準類型 multiprocessing.Process
重寫父類的 run()方法,在方法中定義執行代碼
在使用時建立該自定義進程類型的對象,調用對象的 start()方法啓動一個新的進程數組
import multiprocessing, os class MyProcess(multiprocessing.Process): '''自定義一個進程類型''' def run(self): '''重寫進程處理方法''' print("hello, my name is process:", os.getpid(), os.getppid()) if __name__ == "__main__": print("hello, my name is main:", os.getpid(), os.getppid()) # 建立並啓動一個進程 my_proc = MyProcess() my_proc.start()
多線程的操做模式下咱們的全局變量是多個線程共享的,因此多線程併發模式下對於數據的
修改很是危險,那麼多進程模式下數據的處理應該是什麼樣的呢?
經過兩種方式來觀察多進程模式下數據的處理網絡
參數數據多線程
import multiprocessing, time # 定義全局變量 msg = 3 def chg_numers(): '''定義處理函數,修改全局變量的值''' global msg while msg > 0: msg -= 1 print(multiprocessing.current_process().name, " changed : ", msg) if __name__ == "__main__": # 建立兩個進程,同時修改數據 for i in range(2): p = multiprocessing.Process(target=chg_numers) p.start() time.sleep(2) print(multiprocessing.current_process().name, msg)
進程自己就是一個獨立運行的程序,多進程意味着當前程序被執行了屢次,每一個進程中全局變量的數據都是互相獨立的。併發
import multiprocessing, time def chg_numers(msg): '''定義處理函數,修改全局變量的值''' while msg > 0: msg -= 1 print(multiprocessing.current_process().name, " changed : ", msg) if __name__ == "__main__": # 建立兩個進程,同時修改數據 msg = 3 for i in range(2): p = multiprocessing.Process(target=chg_numers, args=(msg,)) p.start() time.sleep(2) print(multiprocessing.current_process().name, msg)
給多進程併發處理函數傳遞參數的方式,並不能讓數據能夠被多個進程共享
函數執行併發操做時,每一個進程都會單獨拷貝一份當前進程的變量數據進行獨立使用而不互
相影響,這也是出現上述代碼結果的緣由app
多進程的操做在實際應用中也是很是多的,可是純底層的代碼開發控制併發也是一件很是繁
瑣的事情,因此就出現了面向過程多進程併發的優化操做方式:進程池 Pool
經過進程池 Pool 能夠快速建立多個進程執行指定函數,完成高併發處理操做async
名稱 | 描述 |
---|---|
apply(func, args) | 傳遞參數 args 並執行函數 func,同時阻塞當前進程直到該函數執行完成,函數 func 只會在進程池中的一個進程中運行 |
close() | Pool 進程池的底層工做機制是向進程池提交任務產生工做進程執行,該方法是主動中止給進程池提交任務,並等待全部提交任務執行完成退出 |
terminate() | 當即結束該進程,當進程池對象被回收時自動調用該方法 |
join() | 等待工做進程退出,再次之間必須調用 close()或者 teminate |
進程池的基本實現函數
import multiprocessing def my_process(): print("hello my name is : ", multiprocessing.current_process().name) if __name__ == "__main__": # 建立一個進程池對象,該進程池能夠產生兩個處理進程 pool = multiprocessing.Pool(2) # 定義 8 個任務,交給進程池處理 for i in range(8): pool.apply_async(my_process) # 中止提交任務 pool.close() # 獨佔模式:讓主線程等待進程池任務執行完成 pool.join()
能夠看到兩個進程池產生了兩個 工做進程來處理咱們的循環的8個任務高併發
多進程下載
有了進程池,能夠簡單完成一個多進程任務下載的操做處理
該案例只是模擬多進程處理過程,下載任務數據的代碼請參考網絡數據爬蟲技術
import multiprocessing, time def download(url): print(multiprocessing.current_process().name, "開始下載..") time.sleep(0.5) print(multiprocessing.current_process().name,"下載完成<<") time.sleep(2) return "下載的數據" def savedata(data): print(multiprocessing.current_process().name,"下載的數據") if __name__ == "__main__": # 建立進程池 p = multiprocessing.Pool(5) # 任務下載循環 for i in range(20): p.apply_async(download, args=("http://www.dy2018.com",), callback=savedata) # 中止提交任務 p.close() # 獨佔 p.join()
執行時,能夠看到20個任務被進程池中的5個進程平均分配進行了處理
不一樣線程之間的數據通訊,涉及到核心的數據共享問題,主要由PYTHON中提供了內建模塊multiprocessing.Manager類型實現
名稱 | 描述 |
---|---|
Array | 內置進程間共享數組類型 |
Queue | 內置進程間共享隊列類型 |
list() | 內置進程間共享列表類型 |
dict() | 內置進程間共享字典類型 |
Value | 內置進程間共享值類型 |
Barrier | 進程同步類型 |
BoundedSemaphore、Semaphore | 進程信號量類型 |
Lock | RLock |
Event | 進程同步事件類型 |
Condition | 進程同步條件類型 |
多個進程之間的通訊操做,數據的傳遞在PYTHON中的multiprocessing模塊中提供了一個專門用於多進程之間進行數據傳遞的隊列:Queue
名稱 | 描述 |
---|---|
put(data [, timeout=None]) | 添加一個數據到隊列中 |
put_nowait(data) | 添加一個數據到隊列中,非阻塞模式 |
get([timeout=None]) | 從隊列中獲取一個數據 |
get_nowait() | 從隊列中獲取一個數據,非阻塞模式 |
full() | 判斷隊列是否已滿 |
empty() | 判斷隊列是否已空 |
close() | 關閉隊列 |
qsize() | 獲取隊列中的元素數量 |
PYTHON 爲了更加友好的多個進程之間的數據通訊操做,提供了一個管道類型專門用於進程之間的協做:mulriprocessing.Pipe
名稱 | 描述 |
---|---|
init(duplex=True) | 初始化方法,返回兩個數據 conn1,conn2,分別表示管道的兩端,默認是雙向通訊。若是 duplex=False,conn1 只能接受消息,conn2 只能發送消息 |
send(data) | 發送消息 |
recv() | 接受消息 |