併發編程【三】進程

使用multiprocessing模塊操做進程

 一、Process模塊介紹

process模塊是一個建立進程的模塊,藉助這個模塊,就能夠完成進程的建立。html

複製代碼
Process([group [, target [, name [, args [, kwargs]]]]]),由該類實例化獲得的對象,表示一個子進程中的任務(還沒有啓動)

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

參數介紹:
1 group參數未使用,值始終爲None
2 target表示調用對象,即子進程要執行的任務
3 args表示調用對象的位置參數元組,args=(1,2,'egon',)
4 kwargs表示調用對象的字典,kwargs={'name':'egon','age':18}
5 name爲子進程的名稱
複製代碼
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開啓的進程  

方法介紹

方法介紹
方法介紹
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字符的字符串。這個鍵的用途是爲涉及網絡鏈接的底層進程間通訊提供安全性,這類鏈接只有在具備相同的身份驗證鍵時才能成功(瞭解便可)

屬性介紹

屬性介紹
屬性介紹
在Windows操做系統中因爲沒有fork(linux操做系統中建立進程的機制),在建立子進程的時候會自動 import 啓動它的這個文件,而在 import 的時候又執行了整個文件。所以若是將process()直接寫在文件中就會無限遞歸建立子進程報錯。因此必須把建立子進程的部分使用if __name__ ==‘__main__’ 判斷保護起來,import 的時候  ,就不會遞歸運行了。
在windows中使用process模塊的注意事項

二、使用Process模塊建立進程

在python中開啓一個子進程python

複製代碼
import os
import time
from multiprocessing import Process
def func():
    time.sleep(2)
    print(os.getpid(),os.getppid())
if __name__ == "__main__":
    Process(target=func).start()
複製代碼

多個進程同時運行(注意,子進程的執行順序不是根據啓動順序決定的)linux

import time
import random
from multiprocessing import Process
def send_mail(name):
    time.sleep(random.uniform(1,3))
    print('已經給%s發送郵件完畢'%name)
if __name__ == '__main__':
    lst = ['alex','egon','eva_j']
    lis_l = []
    for name in lst:
        p = Process(target=send_mail,args=(name,))
        p.daemon = True
        p.start()
        lis_l.append(p)
    for p in lis_l:p.join() # 異步阻塞
    print('全部的信息都已經發送完畢')

多個進程同時運行
多個進程同時運行

面向對象的方式實現多進程編程

import os
from multiprocessing import Process

class Myprocess(Process):
    def f(self):
        print(11)

    def __init__(self,a,b):
        super().__init__()
        self.a = a
        self.b = b
        # print(a,b)
    def run(self):
        self.f()
if __name__ == '__main__':
    Myprocess(1,2).start()

面向對象的方式實現多進程
View Code

進程與進程之間的數據隔離windows

關於if __name__ == '__main__':

"""
導入模塊的時候其實是運行了一遍這個模塊裏面的內容;
寫的全部代碼是不但願這個文件做爲模塊被導入的時候執行;
咱們就加上if __name__ == '__main'__
"""
在當前文件執行__name__ == 'main'
當該文件做爲模塊被導入的時候 __name__ == '模塊名'

三、守護進程

守護進程會隨着主進程的代碼結束而結束;安全

主進程建立守護進程網絡

  其一:守護進程會在主進程代碼執行結束後就終止併發

  其二:守護進程內沒法再開啓子進程,不然拋出異常:AssertionError: daemonic processes are not allowed to have childrenapp

注意:進程之間是互相獨立的,主進程代碼運行結束,守護進程隨即終止dom

import os
import time
from multiprocessing import Process

class Myprocess(Process):
    def __init__(self,person):
        super().__init__()
        self.person = person
    def run(self):
        print(os.getpid(),self.name)
        print('%s正在和女主播聊天' %self.person)


p=Myprocess('哪吒')
p.daemon=True #必定要在p.start()前設置,設置p爲守護進程,禁止p建立子進程,而且父進程代碼執行結束,p即終止運行
p.start()
time.sleep(10) # 在sleep時查看進程id對應的進程ps -ef|grep id
print('')
建立守護進程
from multiprocessing import Process

def foo():
    print(123)
    time.sleep(1)
    print("end123")

def bar():
    print(456)
    time.sleep(3)
    print("end456")


p1=Process(target=foo)
p2=Process(target=bar)

p1.daemon=True
p1.start()
p2.start()
time.sleep(0.1)
print("main-------")#打印該行則主進程代碼結束,則守護進程p1應該被終止.#可能會有p1任務執行的打印信息123,由於主進程打印main----時,p1也執行了,可是隨即被終止.

主進程代碼執行結束守護進程當即結束
主進程代碼執行結束進程當即結束

四、socket server端併發實列

必定要注意循環導入問題:

 

錯誤示例:

import socket
from multiprocessing import Process
def run(conn):
    while True:
        msg = conn.recv(1024).decode('utf-8')
        print(msg)
if __name__ == '__main__':
    sk = socket.socket()
    sk.bind(('127.0.0.1', 9000))
    sk.listen()
    while 1:
        conn, addr = sk.accept()
        Process(target=run, args=(conn,)).start()

函數式編程實現併發
函數式編程實現併發
import socket
from multiprocessing import Process
class Myprocess(Process):
    def __init__(self,conn):
        super().__init__()
        self.conn = conn
    def run(self):
        while True:
            msg = self.conn.recv(1024).decode('utf-8')
            print(msg)
if __name__ == '__main__':
    sk = socket.socket()
    sk.bind(('127.0.0.1',9000))
    sk.listen()
    while True:
        conn,addr = sk.accept()
        Myprocess(conn).start()

面向對象實現併發
面向對象實現併發

五、多進程的數據共享問題

from multiprocessing import Process
def func(dic):
    dic['count'] -= 1
if __name__ == '__main__':
    dic = {'count':100}
    lis = []
    for i in range(100):
        p = Process(target=func,args=(dic,))
        p.start()
        lis.append(p)
    for j in lis:
        j.join()
    print(dic)     # 進程之間的數據是隔離的{'count': 100}修改不生效

多進程數據隔離
多進程數據隔離
om multiprocessing import Manager
def func(dic):
    dic['count'] -= 1
if __name__ == '__main__':
    m = Manager()             # 管理員
    dic = m.dict({'count': 100})
    lis = []
    for i in range(100):
        p = Process(target=func,args=(dic,))
        p.start()
        lis.append(p)
    for j in lis:
        j.join()
    print(dic)     # 進程之間的數據是隔離的{'count': 5}修改不生效

# 100減100次1這麼慢? 不是減操做形成的 而是開啓進程 管理進程 銷燬進程拖慢了程序的執行速度
# 爲何在這裏出現了數據不安全的現象?
# 什麼狀況下會出現數據不安全 : Manager類當中對字典\列表  += -= *= /=
# 如何解決 : 加鎖

多進程數據共享
多進程數據共享
相關文章
相關標籤/搜索