Python高級編程——12. (1)系統編程之多進程

一.os模塊中的fork方法(只在linux系統中使用,Windows系統不可用)

Pythonos模塊上封裝了常用的系統調用,其中就包括了fork我們可以很輕鬆地在Python代碼中創建進程。


import os, time

def sing():
   for x in range(5):
        print("在唱歌")
        time.sleep(1)


def network():
    for x in range(5):
        print("在上網")
        time.sleep(1)

#  注意:os模塊下的fork()方法在Windows系統中無法使用,只能在Linux系統中使用,比如 Ubuntu 15.04
res = os.fork()

if res == 0:
    sing()

else:
    network()
print("這個程序會執行兩次")

Python中的fork() 函數可以獲得系統中進程的PID ( Process ID ),返回0則爲子進程,否則就是父進程,然後可以據此對運行中的進程進行操作;

  但是強大的 fork() 函數在Windows版的Python中是無法使用的。。。只能在Linux系統中使用,比如 Ubuntu 15.04Windows中獲取父進程ID可以用 getpid()

os.getpid()、os.getppid()(獲得當前進程編號、獲得父進程編號)

我們可以使用os模塊的getpid來獲取當前進程的進程編號,同樣也可以使用os.getppid()方法案來獲取當前進程的父進程編號。

import os import time # 使用os模塊的fork方法可以創建一個新的進程 pid = os.fork() if pid == 0:     while True:         print("我是子線程,我的編號是%s,我的父進程編號是%s" %(os.getpid(),os.getppid()))         time.sleep(1) else:     while True:         print("我是父線程,我的編號是%s,我的子進程編號是%s" %(os.getpid(), pid))         time.sleep(1)

使用os模塊中的getpid()方法,可以得到當前線程的編號,使用getppid()方法可以得到該線程的父級編號。

二、multiprocessing模塊下的Process類實現多進程(通用)

前面我們使用os.fork()方法實現了多進程,但是這種方案只能在Linux下運行,window環境下是無法運行的,那麼有沒有可以實現在任何平臺都能運行的多進程了,有!Python爲大家提供了multiprocessing模塊用來實現多進程。


(1)函數實現方式

#  1.函數實現多進程——無參版
from multiprocessing import Process

def run():
    print("這是一個子進程")

if __name__ == '__main__':
    print("++++++++++++  main start  +++++++++++++")
    t1 = Process(target=run)
    t1.start()
    print("============  main  end   =============")
'''
 運行結果:
++++++++++++  main start  +++++++++++++
============  main  end   =============
這是一個子進程
'''
 # 2.函數實現多進程——有參版
from  multiprocessing  import Process

def run1(msg):
    print("這是一個有參數的子進程,參數爲:   %s"%msg)

if __name__ == '__main__':
    print("++++++++++++  main start  +++++++++++++")
    t1 = Process(target=run1,args=("嘿嘿",))  #  args爲調用的子進程的函數的參數,注意類型是一個元組或者列表。

t1.start()

print("============ main end =============") ''' 運行結果爲: ++++++++++++ main start +++++++++++++ ============ main end ============= 這是一個有參數的子進程,參數爲: 嘿嘿 ''' # 3.多個進程同一函數運行先後順序,順序無法確定 from multiprocessing import Process import time def run2(msg): for x in range(3): print("這是一個有參數的子進程,參數爲: %s"%msg) time.sleep(1) # 人爲的讓代碼停頓,是其他進程有機會搶入 if __name__ == '__main__': print("++++++++++++ main start +++++++++++++") t1 = Process(target=run2,args=("嘿嘿",)) t1.start() t2 = Process(target=run2, args=("哈哈",)) t2.start() t3 = Process(target=run2, args=("呵呵",)) t3.start() print("============ main end =============") '''運行結果: ++++++++++++ main start +++++++++++++ ============ main end ============= 這是一個有參數的子進程,參數爲: 哈哈 這是一個有參數的子進程,參數爲: 嘿嘿 這是一個有參數的子進程,參數爲: 呵呵 這是一個有參數的子進程,參數爲: 哈哈 這是一個有參數的子進程,參數爲: 嘿嘿 這是一個有參數的子進程,參數爲: 呵呵 這是一個有參數的子進程,參數爲: 嘿嘿 這是一個有參數的子進程,參數爲: 哈哈 這是一個有參數的子進程,參數爲: 呵呵 ''' # 4.多函數多進程,順序依然無法確定 from multiprocessing import Process import time def run3(msg): for x in range(3): print("這是第一個有參數的子進程,參數爲: %s111"%msg) time.sleep(1) # 人爲的讓代碼停頓,是其他進程有機會搶入 def run4(msg): for x in range(3): print("這是第二個有參數的子進程,參數爲: %s222" % msg) time.sleep(1) def run5(msg): for x in range(3): print("這是第三個有參數的子進程,參數爲: %s333" % msg) time.sleep(1) if __name__ == '__main__': print("++++++++++++ main start +++++++++++++") t1 = Process(target=run3,args=("嘿嘿",)) t1.start() t2 = Process(target=run4, args=("哈哈",)) t2.start() t3 = Process(target=run5, args=("呵呵",)) t3.start() print("============ main end =============") ''' 運行結果: ++++++++++++ main start +++++++++++++ ============ main end ============= 這是第二個有參數的子進程,參數爲: 哈哈222 這是第一個有參數的子進程,參數爲: 嘿嘿111 這是第三個有參數的子進程,參數爲: 呵呵333 這是第一個有參數的子進程,參數爲: 嘿嘿111 這是第二個有參數的子進程,參數爲: 哈哈222 這是第三個有參數的子進程,參數爲: 呵呵333 這是第一個有參數的子進程,參數爲: 嘿嘿111 這是第二個有參數的子進程,參數爲: 哈哈222 這是第三個有參數的子進程,參數爲: 呵呵333 ''' # 5.讓主進程等待子進程 from multiprocessing import Process def run1(msg): print("這是一個有參數的子進程,參數爲: %s"%msg) if __name__ == '__main__': print("++++++++++++ main start +++++++++++++") t1 = Process(target=run1,args=("嘿嘿",)) t1.start() t1.join() # join方法表示只有子進程執行完成後,主進程才能結束。主進程會等待子進程完成後,自身才會執行完成。 print("============ main end =============") ''' 運行結果爲: ++++++++++++ main start +++++++++++++ 這是一個有參數的子進程,參數爲: 嘿嘿 ============ main end ============= ''' (2)類實現方式
# 1.無參數型,定義一個類,使其繼承自Process類,重寫run方法即可
from multiprocessing import  Process

class MyProcess(Process):
    def run(self):
        print("這是類實現的子進程")

if __name__ == '__main__':
    print("++++++++++++  main  start  +++++++++++++")
    myprocess = MyProcess()
    myprocess.start()
    print("============  main end  ================")
'''
運行結果:
++++++++++++  main  start  +++++++++++++
============  main end  ================
這是類實現的子進程
'''
# 2.有參數型
from multiprocessing import  Process

class MyProcess(Process):
    def __init__(self,name,msg):
        super().__init__(name=name)
        self.msg = msg

    def run(self):
        print("這是類實現的子進程")
        print(self.name)
        print(self.msg)

if __name__ == '__main__':
    print("++++++++++++  main  start  +++++++++++++")
    myprocess = MyProcess("子進程名稱","參數內容")
    myprocess.start()
    print("============  main end  ================")
'''
運行結果:
++++++++++++  main  start  +++++++++++++
============  main end  ================
這是類實現的子進程
子進程名稱
參數內容
'''
三、進程池Pool

from multiprocessing import Pool

def run():
    print("這是一個子進程")
    return 0
def run1():
    print("這是另一個子進程")
    return 1
def cb(msg):
    print("這是一個回調函數,回調函數的參數來自子進程的返回值,返回值爲%s"%msg)

if __name__ == '__main__':
    print("+++++++++++ main start +++++++++++")
    pool = Pool(3)  # 可以設定提前創建的子進程的數目,一般根據項目需求確定
    for x  in range(3):
        pool.apply_async(func=run,callback=cb) # callback爲回調函數,子進程結束後纔會執行
        pool.apply_async(func=run1, callback=cb)
    pool.close()  # 一定要先關閉,後join()
    pool.join()
    print("===========  main end ============")
'''
運行結果:
+++++++++++ main start +++++++++++
這是一個子進程
這是另一個子進程
這是一個回調函數,回調函數的參數來自子進程的返回值,返回值爲0
這是一個子進程
這是一個回調函數,回調函數的參數來自子進程的返回值,返回值爲1
這是一個回調函數,回調函數的參數來自子進程的返回值,返回值爲0
這是另一個子進程
這是一個回調函數,回調函數的參數來自子進程的返回值,返回值爲1
這是一個子進程
這是一個回調函數,回調函數的參數來自子進程的返回值,返回值爲0
這是另一個子進程
這是一個回調函數,回調函數的參數來自子進程的返回值,返回值爲1
===========  main end ============
'''

注意:一般我們使用apply_async這個方法,表示非阻塞的運行,一旦使用了apply方法表示阻塞式執行任務,此時就是單任務執行了(一般不會使用,特殊場景纔會使用)

四、消息隊列Queue\Pipe管道\manager實現進程間的通訊(進程間原本無法通訊,即便是全局變量也是各自使用,不會共享)
(1)消息隊列Queue

我們可以使用multiprocessing模塊中的Queue(消息隊列)來完成多進程間的數據傳遞

我們可以通過queue獲取隊列對象,隊列對象的常用方法如下:

q.put()

q.get()

q.get(item,block=True,timeout=None)

q.put(item,block=True,timeout=None)

q.empty()

q.full()

q.qsize()

q.put_nowait()

q.get_nowait()

from multiprocessing import Process, Pool, Queue
#  Queue隊列的特徵:先進先出,注意queue是線程的隊列,不同於Queue
import time

def sendMsg(q,msg):
    while True:
        print("發送數據:%s>>>>>>>>>>>>>>>>>>>>>>" % msg)
        q.put(msg)
        time.sleep(1)


def accept(q):
    while True:
        print("<<<<<<<<<<<<<<<<<<<<<接收到的數據爲:%s"%q.get())
        time.sleep(1)

if __name__ == '__main__':
    q = Queue(5)  #     表示最多可以推進消息的數量
    new_time = time.time()
    print("++++++++++++++++++  main  start  +++++++++++++++++++++")
    t1 = Process(target=sendMsg, args=(q,"你好嗎?"), name="發送數據進程")
    t1.start()
    t2 = Process(target=accept,args=(q,), name="接收數據進程")
    t2.start()
    print("==================    main  end  ======================", time.time() - new_time)
'''
運行結果:
++++++++++++++++++  main  start  +++++++++++++++++++++
==================    main  end  ====================== 0.03002023696899414
發送數據:你好嗎?>>>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<接收到的數據爲:你好嗎?
發送數據:你好嗎?>>>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<接收到的數據爲:你好嗎?
發送數據:你好嗎?>>>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<接收到的數據爲:你好嗎?
'''
(2)Pipe管道

from multiprocessing import Process,Pipe
import time

def sendMsg(p,msg):
    print("發送數據:%s>>>>>>>>>>>>>>>>>>>>>>" % msg)
    p.send(msg)
    p.close()
    time.sleep(1)

if __name__ == '__main__':
    p1,p2 = Pipe() # Pipe管道返回值有兩個,一個是父進程,一個是子進程
  print(p1,p2)     #   可以將p1,p2打印出來看看
    new_time = time.time()
    print("++++++++++++++++++  main  start  +++++++++++++++++++++")
    t1 = Process(target=sendMsg, args=(p1,"你好嗎?"), name="發送數據進程")
    t1.start()
    print("<<<<<<<<<<<<<<<接收到的數據爲:%s"%p2.recv())
    print("==================    main  end  ======================", time.time() - new_time)
'''
運行結果:
<multiprocessing.connection.PipeConnection object at 0x0000023B3CDC1F28> <multiprocessing.connection.PipeConnection object at 0x0000023B3CBE72B0>
++++++++++++++++++  main  start  +++++++++++++++++++++
發送數據:你好嗎?>>>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<接收到的數據爲:你好嗎?
==================    main  end  ====================== 0.2751955986022949
'''
(3)manager

之前我們學習進程間的數據通信僅僅只是數據的傳遞,而不是數據的共享,那麼如果我們想實現進程間的數據共享應該怎麼做呢?使用Manager來實現。

Managers支持的數據類型有listdict、NamespaceLockRlockQueue、Value、Array and so on


from multiprocessing import Process, Manager

def saveDatas(lists, dicts):
    lists.append("武松")
    lists.append("潘金蓮")
    lists.append("武大郎")
    dicts["name"] = "姜子牙"
    dicts["age"] = 80
    dicts["mp"] = 50
    print(lists)
    print(dicts)

if __name__ == '__main__':
    print("++++++++++++++  main  start +++++++++++++++++++")
    # manager = Manager()  # 獲取一個Manager對象
    with Manager() as manager:  # <==>manager = Manager()
        lists = manager.list()  # 普通的list無法跨越多進程,只有manager中的list可以
        dicts = manager.dict()
        ls = []
        #  啓動線程
        for x in range(5):
            task = Process(target=saveDatas, args=(lists, dicts))
            task.start()
            ls.append(task)
            # 如果join()方法寫在這裏,則是一個進程結束後纔開始第二個進程,進程之間數據同步,類似於單進程
        #
        for i in ls:
            i.join() # manager 也要藉助於join()方法來迫使主進程等待子進程的運行

    print("================  main  end ================")
'''
運行結果:++++++++++++++  main  start +++++++++++++++++++
['武松', '潘金蓮', '武大郎']
{'age': 80, 'mp': 50, 'name': '姜子牙'}
['武松', '潘金蓮', '武大郎', '武松', '潘金蓮', '武大郎']
{'age': 80, 'mp': 50, 'name': '姜子牙'}
['武松', '潘金蓮', '武大郎', '武松', '潘金蓮', '武大郎', '武松', '潘金蓮', '武大郎']
{'age': 80, 'mp': 50, 'name': '姜子牙'}
['武松', '潘金蓮', '武大郎', '武松', '潘金蓮', '武大郎', '武松', '潘金蓮', '武大郎', '武松', '潘金蓮', '武大郎']
{'age': 80, 'mp': 50, 'name': '姜子牙'}
['武松', '潘金蓮', '武大郎', '武松', '潘金蓮', '武大郎', '武松', '潘金蓮', '武大郎', '武松', '潘金蓮', '武大郎', '武松', '潘金蓮', '武大郎']
{'age': 80, 'mp': 50, 'name': '姜子牙'}
================  main  end ================                 
'''

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章