1. 程式人生 > >python建立子程序的幾種常用方式(fork, Process,程序池)

python建立子程序的幾種常用方式(fork, Process,程序池)

linux下使用fork()建立子程序

Linux 作業系統提供了一個 fork() 函式用來建立子程序,這個函式很特殊,呼叫一次,返回兩次,因為作業系統是將當前的程序(父程序)複製了一份(子程序),然後分別在父程序和子程序內返回。子程序永遠返回0,而父程序返回子程序的 PID(大於0)。我們可以通過判斷返回值是不是 0 來判斷當前是在父程序還是子程序中執行。

在 Python 中同樣提供了 fork() 函式,此函式位於 os 模組下。

例子:

import os
import time

ret = os.fork()         #建立了一個子程序
if ret == 0:        #子程序
while True: print("-------1--------") time.sleep(1) else: #父程序 while True: print("-------2--------") time.sleep(1)

輸出結果為:

-------2--------
-------1--------
-------1--------
-------2--------
-------1--------
-------2--------
-------1--------
-------2-------- -------1-------- -------2-------- -------1-------- -------2-------- -------1-------- -------2--------

無限迴圈。。。。。。(注:子程序和父程序的執行順序不確定,即1和2輸出順序不一定,由作業系統的排程演算法確定)

注意:如果父程序結束,子程序也跟著結束
如程式:

import os
import time

ret = os.fork()
if ret == 0:
    while True:
        print("---1-----")
        time
.sleep(1) else: print("---2-----")

輸出結果為:

---2-----
---1-----

使用Process建立子程序

linux下可以使用fork建立子程序,但windows下不支援fork函式,但可以使用Process建立子程序

注意:與fork不同的是,主程序會等待Process子程序完成後結束。

Process語法結構如下:

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

target:表示這個程序例項所呼叫物件;

args:表示呼叫物件的位置引數元組;

kwargs:表示呼叫物件的關鍵字引數字典;

name:為當前程序例項的別名;

group:大多數情況下用不到;

Process類常用方法:

is_alive():判斷程序例項是否還在執行;

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

start():啟動程序例項(建立子程序);

run():如果沒有給定target引數,對這個物件呼叫start()方法時,就將執行物件中的run()方法;

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

Process類常用屬性:

name:當前程序例項別名,預設為Process-N,N為從1開始遞增的整數;

pid:當前程序例項的PID值;

from multiprocessing import Process
import time
import random

def test():
    for i in range(1,5):
        print("---%d---"%i)
        time.sleep(1)

p = Process(target=test)
p.start()   #讓這個程序開始執行test函式裡面的程式碼

p.join()     #等程序p結束之後,才會繼續向下走
print("---main----")

輸出結果為:

---1---
---2---
---3---
---4---
---main----

程序池建立子程序

當需要建立的子程序數量不多時,可以直接利用multiprocessing中的Process動態成生多個程序,但如果是上百甚至上千個目標,手動的去建立程序的工作量巨大,此時就可以用到multiprocessing模組提供的Pool方法。

初始化Pool時,可以指定一個最大程序數,當有新的請求提交到Pool中時,如果池還沒有滿,那麼就會建立一個新的程序用來執行該請求;但如果池中的程序數已經達到指定的最大值,那麼該請求就會等待,直到池中有程序結束,才會建立新的程序來執行.

multiprocessing.Pool常用函式解析:

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

apply(func[, args[, kwds]]):使用阻塞方式呼叫func

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

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

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

程式(非阻塞方式):

from multiprocessing import Pool
import os
import time

def worker(num):
    for i in range(2):
        print("===pid=%d===num=%d"%(os.getpid(), num))
        time.sleep(1)

pool = Pool(3)  #定義一個程序池,最大程序數3

for i in range(5):
    print("---%d---"%i)
    pool.apply_async(worker, [i,])    #使用非阻塞方式呼叫func(並行執行,堵塞方式必須
                                      #等待上一個程序退出才能執行下一個程序)

print("---start----")
pool.close()    #關閉程序池,關閉後pool不能再新增新的請求
pool.join()     #等待pool中所有子程序執行完成,必須放在close語句之後
print("---end----")

輸出:

---0---
---1---
---2---
---3---
---4---
---start----
===pid=24958===num=0
===pid=24959===num=1
===pid=24960===num=2
===pid=24958===num=0
===pid=24960===num=2
===pid=24959===num=1
===pid=24960===num=3
===pid=24958===num=4
===pid=24960===num=3
===pid=24958===num=4
---end----

程式(阻塞方式):

from multiprocessing import Pool
import os
import time

def worker(num):
    for i in range(2):
        print("===pid=%d===num=%d"%(os.getpid(), num))
        time.sleep(1)

pool = Pool(3)  #定義一個程序池,最大程序數3

for i in range(5):
    print("---%d---"%i)
    pool.apply(worker, [i,])    #使用非阻塞方式呼叫func(並行執行,堵塞方式必須
                                      #等待上一個程序退出才能執行下一個程序)

print("---start----")
pool.close()    #關閉程序池,關閉後pool不能再新增新的請求
pool.join()     #等待pool中所有子程序執行完成,必須放在close語句之後
print("---end----")

輸出:

---0---
===pid=24999===num=0
===pid=24999===num=0
---1---
===pid=25000===num=1
===pid=25000===num=1
---2---
===pid=25001===num=2
===pid=25001===num=2
---3---
===pid=24999===num=3
===pid=24999===num=3
---4---
===pid=25000===num=4
===pid=25000===num=4
---start----
---end----

注意:程序池和fork()一樣,不會等待子程式結束

例子:

from multiprocessing import Pool
import os
import time

def worker():
    for i in range(2):
        print("===pid=%d==="%os.getpid())
        time.sleep(1)

pool = Pool(3)  #定義一個程序池,最大程序數3

for i in range(5):
    print("---%d---"%i)
    pool.apply_async(worker)    #使用非阻塞方式呼叫func(並行執行,堵塞方式必須
                                #等待上一個程序退出才能執行下一個程序)

輸出:

---0---
---1---
---2---
---3---
---4---