一、模塊介紹
-
multiprocess模快
仔細說來,multiprocess不是一個模塊,而是python中的一個操作、管理進程的包,之所以叫multi是取自multiple的多功能的意思,這個包中幾乎包含了和進程有關的所有子模塊。 -
multiprocess.Process模塊
Process能夠幫助我們創建子進程,以及對子進程的一些控制.
- 參數:def __init__(self, group=None, target=None, name=None, args=(), kwargs={}):
group=None:該參數未使用,值始終爲None
target:指定要調用的函數,即子進程要執行的任務
args:指定被調用對象的位置參數,以元組的形式傳入,必須有逗號,如:args=('a',);此參數在源碼中定義的只接收元組,但由於tuple數據類型底層原理的原因,此參數是可以傳入一切可迭代對象,如:列表、字典、字符串、生成器表達式等
kwargs:指定被調用對象關鍵字參數,以字典的形式傳入,關鍵字作爲鍵,參數作爲值
name:指定子進程的名稱,默認名稱爲:Process-1、Process-2、...
- 方法
obj.start():啓動子進程,並調用run()方法
obj.run():啓動子進程時自動被調用,正是它去調用target參數指定的函數,自定義類中必須實現此方法
obj.terminate():強制終止子進程,不會進行任何清理操作,事實上是讓操作系統去終止子進程;而操作系統終止進程是有一個過程的,所以子進程不會立即被終止;使用此方法需謹慎以下兩種情況:1. 如果子進程中創建了子子進程,強制終止子進程後,子子進程將變成殭屍進程. 2. 如果子進程保存了一個鎖,強制終止後,內存將不會被釋放,進而導致死鎖
obj.is_alive():判斷子進程是否存活,若存活返回True,否則False
obj.join(timeout=None):阻塞父進程,等待子進程終止後再繼續執行父進程,timeout指定等待超時時間;此方法只能用於使用start方法啓動的子進程,對run方法啓動的子進程無效
屬性
obj.daemon:默認值爲False,如果設爲True,子進程將成爲守護進程,此屬性必須寫在start()的前面;守護進程無法創建子進程,且會隨着父進程的終止而終止
obj.name:放回子進程的名稱
obj.pid:放回子進程的pid
obj.exitcode:子進程在運行時爲None,如果爲-N,則表示被信號N結束了
obj.authkey:子進程的身份驗證鍵,默認由os.urandom()隨機成生成的32bytes;是爲涉及網絡連接的底層進程間通訊提供安全性,這類連接只有在具有相同身份驗證鍵時才能成功
二、使用Process創建進程
- windows系統使用Process模塊需注意
由於windows操作系統中沒有fork(Linux操作系統中創建進程的機制),因此啓動子進程時採用的是導入啓動子進程的文件的方式來完成進程間的數據共享。而導入文件即等於執行文件,因此如果將process()直接寫在文件中將會無限遞歸子進程而報錯,所以必須把創建子進程的部分使用if __name__ == '__main__':判斷保護起來,以防止遞歸.
1. 基本操作
# 創建單個子進程及對子進程簡單的控制
from multiprocessing import Process
from time import sleep
import os
def func(par):
print("%s, PID: %s" %(par, os.getpid()))
print("子進程終止後才繼續執行父進程")
sleep(5)
if __name__ == '__main__':
p = Process(target=func, args=("子進程",)) # 實例化一個子進程對象p
# p.run() # run方法啓動的子進程免疫join方法
p.start() # 子進程進入就緒狀態,等待操作系統調度
print(p.is_alive()) # True: 子進程存活
p.join(1) # 阻塞父進程,等待子進程終止,等待超時時間1s
print(p.is_alive()) # False: 子進程終止
print("父進程, PID: %s" % os.getpid())
# 創建多個子進程
from multiprocessing import Process
from time import sleep
def func(n):
print("子進程", n)
sleep(0.1)
if __name__ == '__main__':
p_lst = []
for i in range(5): # 通過for循環啓動多個子進程
p = Process(target=func, args=(i,))
p.start()
p_lst.append(p)
[p.join() for p in p_lst] # 阻塞父進程,等待所有子進程終止
print("父進程")
2. 自定義多進程類
# 自定義多進程類
from multiprocessing import Process
from time import sleep
class MyProcess(Process):
def __init__(self, target, name, sex):
self.sex = sex
super(MyProcess, self).__init__(target=target, name=name)
# self.name = name
# 父類Process初始化時會自動定義name屬性,所以定義本類的name屬性要寫到super語句後面,
# 否則會被父類初始化時覆蓋掉(MyProcess-子進程序號),或者給父類傳參__init__(name=name)
def run(self): # 必寫方法,用於調用函數
print("子進程:", self.name)
super(MyProcess, self).run()
func = lambda :print("執行了函數")
# 如果是Windows系統,此處要寫一條__main__判斷語句
p = MyProcess(func, 'zyk', 'boy')
p.start()
# p.run() # start方法會自動調用此方法
3.進程之間的數據共享與隔離
# 進程之間的數據共享與隔離
from multiprocessing import Process
def func():
global n
print("1.子進程", n) # 1.子進程 1
n = 2 # 不會影響父進程中的變量n
print("2.子進程", n) # 2.子進程 2
if __name__ == '__main__':
n = 1
p = Process(target=func)
p.start()
p.join()
print("父進程", n) # 父進程 1
4.守護進程
# 守護進程
from multiprocessing import Process
from os import getpid
class MyProcess(Process):
def __init__(self, name):
super(MyProcess, self).__init__()
self.name = name
def run(self):
print(self.name, getpid())
# 父進程是先進入就緒狀態的,所以父進程一般會先終止(除非父進程還有很長的邏輯要走)
# 子進程可能還未打印信息便隨父進程終止而終止了,
p = MyProcess('zyk')
p.daemon = True # 確認爲守護進程,隨父進程終止而終止
p.start()
# p.join() # 阻塞父進程,方可正常執行完子進程,而顯示打印信息
print("父進程")
5.進階:socket消息加併發實例
# Server
from multiprocessing import Process
from socket import *
server = socket(AF_INET, SOCK_STREAM)
server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
server.bind(('127.0.0.1', 8080))
server.listen(5)
def talk(conn, client_addr):
while True:
try:
msg = conn.recv(1472)
if not msg:break
conn.send(msg.upper())
except Exception:
break
if __name__ == '__main__':
while 1:
conn, client_addr = server.accept()
p = Process(target=talk, args=(conn, client_addr))
p.start()
print(p.name)
# Client
import socket
client = socket.socket()
client.connect_ex(('127.0.0.1', 8080))
while 1:
msg = input('>>>').strip()
if not msg:continue
client.send(msg.encode('utf-8'))
msg = client.recv(1472)
print(msg.decode('utf-8'))
完結