python創建進程的常用方式


  運行程序時,單線程或單進程往往是比較慢的,為加快程序運行速度,我們可以使用多進程,可以理解為多任務同時運行,小編的電腦是四核,所以可以設置四個進程。

下面,我們來了解下多進程的使用:

1、使用multiprocessing模塊創建進程

  multiprocessing模塊提供了一個Process類來代表進程對象,語法如下:

  Process([group[,target[,name[,args[,kwargs]]]]])

  其中,group:參數未使用,值始終是None

  target:表示當前進程啟動時執行的可調用對象

  name:為當前進程實例的別名

  args:表示傳遞給target函數的參數元組

  kwargs:表示傳遞給target函數的參數字典

使用多進程的一個簡單例子:

from multiprocessing import Process     # 導入模塊

# 執行子進程代碼
def test(interval):
    print('我是子進程')
# 執行主程序
def main():
    print('主進程開始')
    # 實例化Procss進程類
    p = Process(target=test,args=(1,))
    # 啟動子進程
    p.start()
    print('主進程結束')

if __name__ == '__main__':
    main()

結果:

主進程開始
主進程結束
我是子進程

  Process的實例p常用的方法除start()外,還有如下常用方法:

  is_alive():判斷進程實例是否還在執行

  join([timeout]):是否等待進程實例執行結束,或等待多少秒

  start():啟動進程實例(創建子進程)

  run():如果沒有給定target參數,對這個對象調用start()方法時,就將執行對象中的run()方法

  terminate():不管任務是否完成,立即終止

  Process類還有如下常用屬性:

  name:當前進程實例別名,默認為Process-N,N為從1開始遞增的整數

  pid:當前進程實例的PID值

下面是Process類方法和屬性的使用,創建兩個子進程,分別使用os模塊和time模塊輸出父進程和子進程的id以及子進程的時間,並調用Process類的name和pid屬性:

# -*- coding:utf-8 -*-
from multiprocessing import Process
import time
import os

#兩個子進程將會調用的兩個方法
def  child_1(interval):
    print("子進程(%s)開始執行,父進程為(%s)" % (os.getpid(), os.getppid()))
    # 計時開始
    t_start = time.time()
    # 程序將會被掛起interval秒
    time.sleep(interval)
    # 計時結束
    t_end = time.time()
    print("子進程(%s)執行時間為'%0.2f'秒"%(os.getpid(),t_end - t_start))

def  child_2(interval):
    print("子進程(%s)開始執行,父進程為(%s)" % (os.getpid(), os.getppid()))
    # 計時開始
    t_start = time.time()
    # 程序將會被掛起interval秒
    time.sleep(interval)
    # 計時結束
    t_end = time.time()
    print("子進程(%s)執行時間為'%0.2f'秒"%(os.getpid(),t_end - t_start))

if __name__ == '__main__':
    print("------父進程開始執行-------")
    # 輸出當前程序的ID
    print("父進程PID:%s" % os.getpid())
    # 實例化進程p1
    p1=Process(target=child_1,args=(1,))
    # 實例化進程p2
    p2=Process(target=child_2,name="mrsoft",args=(2,))
    # 啟動進程p1
    p1.start()
    # 啟動進程p2
    p2.start()
    #同時父進程仍然往下執行,如果p2進程還在執行,將會返回True
    print("p1.is_alive=%s"%p1.is_alive())
    print("p2.is_alive=%s"%p2.is_alive())
    #輸出p1和p2進程的別名和PID
    print("p1.name=%s"%p1.name)
    print("p1.pid=%s"%p1.pid)
    print("p2.name=%s"%p2.name)
    print("p2.pid=%s"%p2.pid)
    print("------等待子進程-------")
    # 等待p1進程結束
    p1.join()
    # 等待p2進程結束
    p2.join()
    print("------父進程執行結束-------")

結果:

------父進程開始執行-------
父進程PID:13808
p1.is_alive=True
p2.is_alive=True
p1.name=Process-1
p1.pid=13360
p2.name=mrsoft
p2.pid=21500
------等待子進程-------
子進程(13360)開始執行,父進程為(13808)
子進程(21500)開始執行,父進程為(13808)
子進程(13360)執行時間為'1.01'秒
子進程(21500)執行時間為'2.00'------父進程執行結束-------

  上述代碼中,第一次實例化Process類時,會為name屬性默認賦值為Process-1,第二次則默認為Process-2,但由於實例化進程p2時,設置了name屬性為mrsoft,所以p2.name的值為mrsoft。

2、使用Process子類創建進程

  對於一些簡單的小任務,通常使用Process(target=test)方式實現多進程。但如果要處理復雜任務的進程,通常定義一個類,使其繼承Process類,下面是通過使用Process子類創建多個進程。

# -*- coding:utf-8 -*-
from multiprocessing import Process
import time
import os

#繼承Process類
class SubProcess(Process):
    # 由於Process類本身也有__init__初識化方法,這個子類相當於重寫了父類的這個方法
    def __init__(self,interval,name=''):
        # 調用Process父類的初始化方法
        Process.__init__(self)
        # 接收參數interval
        self.interval = interval
        # 判斷傳遞的參數name是否存在
        if name:
            # 如果傳遞參數name,則為子進程創建name屬性,否則使用默認屬性
            self.name = name        
    #重寫了Process類的run()方法
    def run(self):
        print("子進程(%s) 開始執行,父進程為(%s)"%(os.getpid(),os.getppid()))
        t_start = time.time()
        time.sleep(self.interval)
        t_stop = time.time()
        print("子進程(%s)執行結束,耗時%0.2f秒"%(os.getpid(),t_stop-t_start))

if __name__=="__main__":
    print("------父進程開始執行-------")
    # 輸出當前程序的ID
    print("父進程PID:%s" % os.getpid())                  
    p1 = SubProcess(interval=1,name='mrsoft')
    p2 = SubProcess(interval=2)
    #對一個不包含target屬性的Process類執行start()方法,就會運行這個類中的run()方法,
    #所以這里會執行p1.run()
    # 啟動進程p1
    p1.start()
    # 啟動進程p2
    p2.start()  
    # 輸出p1和p2進程的執行狀態,如果真正進行,返回True,否則返回False
    print("p1.is_alive=%s"%p1.is_alive())
    print("p2.is_alive=%s"%p2.is_alive())
    #輸出p1和p2進程的別名和PID
    print("p1.name=%s"%p1.name)
    print("p1.pid=%s"%p1.pid)
    print("p2.name=%s"%p2.name)
    print("p2.pid=%s"%p2.pid)
    print("------等待子進程-------")
    # 等待p1進程結束
    p1.join()
    # 等待p2進程結束
    p2.join() 
    print("------父進程執行結束-------")

結果:

------父進程開始執行-------
父進程PID:2512
p1.is_alive=True
p2.is_alive=True
p1.name=mrsoft
p1.pid=20328
p2.name=SubProcess-2
p2.pid=13700
------等待子進程-------
子進程(20328) 開始執行,父進程為(2512)
子進程(13700) 開始執行,父進程為(2512)
子進程(20328)執行結束,耗時1.00秒
子進程(13700)執行結束,耗時2.00秒
------父進程執行結束-------

  上述代碼中,定義了一個SubProcess子類,繼承multiprocess.Process父類。SubProcess子類中定義了兩個方法:__init__()初始化方法和run()方法,在__init__()初始化方法中,調用父類multiprocess.Process的__init__()初始化方法,否則父類的__init__()方法會被覆蓋,無法開啟進程。此外,在SubProcess子類中沒有定義start()方法,但在主程序中卻調用了start()方法,此時就會自動執行SubProcess類的run()方法。

3、使用進程池Pool創建進程

  上面我們使用Process類創建了兩個進程,但如果要創建十幾個或者上百個進程,則需要實例化更多的Process類,解決這一問題的方法就是使用multiprocessing模塊提供的pool類,即Pool進程池。

  我們先來了解下Pool類的常用方法:

  apply_async(func[,args[,kwds]]):使用非阻塞方式調用func()函數(並行執行,阻塞方式必須等待上一個進程退出才能執行下一個進程),args為傳遞給func()函數的參數列表, kwds為傳遞給func()函數的關鍵字參數列表

  apply(func[,args[,kwds]]):使用阻塞方式調用func()函數

  close():關閉Pool,使其不再接受新的任務

  terminate():不管任務是否完成,立即終止

  join():主進程阻塞,等待子進程的退出,必須在close或terminate之后使用

  下面通過一個示例演示一下如何通過進程池創建多進程,設置最大進程數為3,使用非阻塞方式執行10個任務:

# -*- coding=utf-8 -*-
from multiprocessing import Pool
import os, time

def task(name):
    print('子進程(%s)執行task %s ...' % ( os.getpid() ,name))
    # 休眠1秒
    time.sleep(1)       

if __name__=='__main__':
    print('父進程(%s).' % os.getpid())
    # 定義一個進程池,最大進程數3
    p = Pool(3)        
    # 從0開始循環10次   
    for i in range(10):
        # 使用非阻塞方式調用task()函數 
        p.apply_async(task, args=(i,))    
    print('等待所有子進程結束...')
    # 關閉進程池,關閉后p不再接收新的請求
    p.close()
    # 等待子進程結束
    p.join()    
    print('所有子進程結束.')

結果:

父進程(3856).
等待所有子進程結束...
子進程(18872)執行task 0 ...
子進程(11220)執行task 1 ...
子進程(10140)執行task 2 ...
子進程(18872)執行task 3 ...
子進程(11220)執行task 4 ...
子進程(10140)執行task 5 ...
子進程(18872)執行task 6 ...
子進程(11220)執行task 7 ...
子進程(10140)執行task 8 ...
子進程(18872)執行task 9 ...
所有子進程結束.

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM