1. 程式人生 > >並發編程之多進程

並發編程之多進程

示例 min 類實例化 eas timeout 守護進程 優勢 stream main

multiprocessing模塊

python中的多線程無法利用多核優勢,如果想要充分地使用多核CPU的資源(os.cpu_count()查看),在python中大部分情況需要使用多進程。Python提供了multiprocessing。
multiprocessing模塊用來開啟子進程,並在子進程中執行我們定制的任務(比如函數),該模塊與多線程模塊threading的編程接口類似。

  multiprocessing模塊的功能眾多:支持子進程、通信和共享數據、執行不同形式的同步,提供了Process、Queue、Pipe、Lock等組件。

需要再次強調的一點是:與線程不同,進程沒有任何共享狀態,進程修改的數據,改動僅限於該進程內。

Process類

1.創建進程的類

Process([group [, target [, name [, args [, kwargs]]]]]),由該類實例化得到的對象,表示一個子進程中的任務(尚未啟動)

強調:
1. 需要使用關鍵字的方式來指定參數
2. args指定的為傳給target函數的位置參數,是一個元組形式,必須有逗號

2.參數

group參數未使用,值始終為None

target表示調用對象,即子進程要執行的任務

args表示調用對象的位置參數元組,args=(1,2,egon,)

kwargs表示調用對象的字典,kwargs={name:‘zhou
,age:18} name為子進程的名稱

3.方法

p.start():啟動進程,並調用該子進程中的p.run() 
p.run():進程啟動時運行的方法,正是它去調用target指定的函數,我們自定義類的類中一定要實現該方法  

p.terminate():強制終止進程p,不會進行任何清理操作,如果p創建了子進程,該子進程就成了僵屍進程,使用該方法需要特別小心這種情況。
如果p還保存了一個鎖那麽也將不會被釋放,進而導致死鎖
p.is_alive():如果p仍然運行,返回True p.join([timeout]):主線程等待p終止(強調:是主線程處於等的狀態,而p是處於運行的狀態)。timeout是可選的超時時間,需要強調的是
,p.join只能join住start開啟的進程,而不能join住run開啟的進程

4.屬性

p.daemon:默認值為False,如果設為True,代表p為後臺運行的守護進程,當p的父進程終止時,p也隨之終止,並且設定為True後,p不能創建自己的新進程,必須在p.start()之前設置

p.name:進程的名稱

p.pid:進程的pid

p.exitcode:進程在運行時為None、如果為–N,表示被信號N結束(了解即可)

p.authkey:進程的身份驗證鍵,默認是由os.urandom()隨機生成的32字符的字符串。這個鍵的用途是為涉及網絡連接的底層進程間通信提供安全性,這類連接只有在具有相同的身份驗證鍵時才能成功(了解即可)

Process類的使用

1.註意

在windows中Process()必須放到# if __name__ == ‘__main__‘:下

技術分享
Since Windows has no fork, the multiprocessing module starts a new Python process and imports the calling module. 
If Process() gets called upon import, then this sets off an infinite succession of new processes (or until your machine runs out of resources). 
This is the reason for hiding calls to Process() inside

if __name__ == "__main__"
since statements inside this if-statement will not get called upon import.
由於Windows沒有fork,多處理模塊啟動一個新的Python進程並導入調用模塊。 
如果在導入時調用Process(),那麽這將啟動無限繼承的新進程(或直到機器耗盡資源)。 
這是隱藏對Process()內部調用的原,使用if __name__ == “__main __”,這個if語句中的語句將不會在導入時被調用。
解釋

2.開啟子進程的兩種方法

#開進程的方法一:
import time
import random
from multiprocessing import Process  #導入Process類
def piao(name):
    print(%s piaoing %name)
    time.sleep(random.randrange(1,5))
    print(%s piao end %name)



p1=Process(target=piao,args=(zhangsan,)) #必須加,號
p2=Process(target=piao,args=(lisi,))
p3=Process(target=piao,args=(wangwu,))
p4=Process(target=piao,args=(xiaoming,))

p1.start()
p2.start()
p3.start()
p4.start()

#可以簡寫為
#p_list = [p1,p2,p3,p4]
#
#for p in p_list:
#  p.start()
print(主線程)


#開進程的方法二:
import time
import random
from multiprocessing import Process


class Piao(Process):
    def __init__(self,name):
        super().__init__()   #繼承父類Process的__init__方法
        self.name=name
    def run(self):    #必須有run這個方法
        print(%s piaoing %self.name)

        time.sleep(random.randrange(1,5))
        print(%s piao end %self.name)

p1=Piao(egon)
p2=Piao(alex)
p3=Piao(wupeiqi)
p4=Piao(yuanhao)

p1.start() #start會自動調用run
p2.start()
p3.start()
p4.start()
print(主線程)

3.進程之間的內存空間是隔離的

from multiprocessing import Process
n=100 #在windows系統中應該把全局變量定義在if __name__ == ‘__main__‘之上就可以了
def work():
    global n
    n=0
    print(子進程內: ,n)


if __name__ == __main__:
    p=Process(target=work)
    p.start()
    print(主進程內: ,n)

#主進程內:100
#子進程內:0

4. 示例: TCP通訊並發

技術分享
import socket
from multiprocessing import Process

phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #就是它,在bind前加
phone.bind((127.0.0.1,8082))

phone.listen(5)

def func(conn):
    while True: #通信循環
        try:
            cmd=conn.recv(1024) #最大收1024
            if not cmd:break #針對linux
            conn.send(cmd.upper())
        except Exception:
            break
    conn.close()
if __name__ == __main__:
    while True: #連接循環
        print(starting...)
        conn,addr=phone.accept()
        print(IP:%s,PORT:%s %(addr[0],addr[1]))
        p = Process(target=func,args=(conn,))
        p.start()

    #7、關機
    phone.close()
服務端 技術分享
import socket
#1、買手機
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

#2、打電話
phone.connect((127.0.0.1,8082))

#3、發收消息a
while True:
    msg=input(>>: ).strip()
    if not msg:continue
    phone.send(msg.encode(utf-8))
    print(has send===>)
    data=phone.recv(1024)
    print(has recv)
    print(data.decode(utf-8))

#4、掛電話
phone.close()
客戶端

並發編程之多進程