天天看點

【Python 多程序】

"

一、子產品介紹

  1. multiprocess模快

    仔細說來,multiprocess不是一個子產品,而是python中的一個操作、管理程序的包,之是以叫multi是取自multiple的多功能的意思,這個包中幾乎包含了和程序有關的所有子子產品。

  2. 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, Value

def func():

global n # !

n = 2 # 資料隔離:不會影響父程序中的變量n

print("子程序n: ", n) # 2

s.value = 4 # 資料共享:會影響父程序中的s

print("子程序s: ", s.value)

if __name__ == '__main__':

n = 1

s = Value('i', 3)

p = Process(target=func)

p.start()

p.join()

print("父程序n: ", n) # 1

print("父程序s: ", s.value) # 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("父程序")

# 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'))