python開發 *進程數據隔離.守護進程,進程同步工具 * 180725

進程數據隔離.守護進程,進程同步工具


一.進程之間的數據隔離:
from multiprocessing import Process
n=100       #主程序中變量n=
def func():

    global n      #子進程中引用父進程中變量n,
    n=n-1
    return 111
if __name__=="__main__":  # "子進程必須寫在它下面"
    n_l=[]                 # 建立一個新列表
    for i in range(100):    #計數
        p=Process(target=func)    #建立一個子進程,子進程對象是func
        p.start()       #向操做系統申請開啓一個子進程  自動執行run 方法
        n_l.append(p)            # 將每個子進程添加到列表中
    print(n_l)   #列表裏是相似於<Process(Process-1, stopped)>的元素
    for p in n_l:  #循環遍歷  每個元素
        p.join()    #全部子進程都結束在執行下面的程序

    print(n)      #100     #結果=100 顯然子進程並無引用到父進程的變量.

 



進程之間的數據隔離:
總結:
1.進程與進程之間數據是隔離的,
2.內存空間是不能共享的
3.因此想要進行通訊,必須藉助其餘手段,且這兩個進程都是自願的.
4.子進程的執行結果父進程獲取不到
5.父進程如何獲取子進程的執行結果:經過socket通訊.

二.守護進程:
import time
from multiprocessing import Process
例一.
def func():
print("begin")
time.sleep(3)
print("wahaha")
if __name__=="__main__":
p=Process(target=func)
p.daemon=True
注意:
# 屬性:守護進程的屬性,默認是False,若是設置成True,就表示設置這個子進程爲一個守護進程
# 守護進程的位置:設置守護進程的操做應該在開啓子進程以前

p.start()
time.sleep(1)
print("主進程") #結果 只打印begin 主進程,
#例二:
def func1():
    print("begin")               #2打印begin
    time.sleep(3)                 #3 休三秒
    print("wahaha")              #12.打印 wahaha
def func2():
    while True:
        print("in func2")        #7.打印 in func2   9.打印infunc2
        time.sleep(0.5)           #8.睡0.5秒
if __name__=="__main__":
    Process(target=func1).start()   #1 建立一個子進程,子進程對象爲func1,並向操做系統申請開啓
    p=Process(target=func2)         #4 再建立一個子進程,子進程對象爲func2,
    p.daemon=True                   #5.設置守護進程操做
    p.start()                       # 6.申請開啓子進程func2
    time.sleep(1)                   #10睡 1秒
    print("主進程")                #11.打印主進程

  


總結:
守護進程會在主進程的代碼執行完畢以後直接結束,不管守護進程是否執行完畢
應用:
報活 主進程還活着
爲何要用守護進程來報活,不用主進程來工做?
守護進程報活幾乎不佔用CPU,也不須要操做系統去調度
主進程不能嚴格的每60秒就發送一條信息.

三.進程同步的工具
相關知識:
進程 : 同一時刻能夠作多件事情 互相之間不影響
進程之間是異步;
進程同步的工具:鎖( Lock ),信號量( Semaphore ) ,事件( Event )
同步:有前後順序
(一). 鎖Lock
    from multiprocessing import Lock
    lock=Lock()    #建立一把鎖
    #兩個方法
    lock.acquire() #獲取這把鎖的鑰匙
    lock.release() #歸還這把鎖的鑰匙
#搶票的例子(每一個人都能查看餘票,買票

import json      #導入json模塊
import time      #導入時間模塊
from multiprocessing import Process  #導入Process模塊
from multiprocessing import Lock      #導入Lock模塊
def search(i):#定義一個查票函數
    with open("db","r")as f:                                    # 2 打開文件,讀取文件數據
        count_dic=json.load(f)                                    # 3 將讀取數據反序列化獲得數據自己
        time.sleep(0.2)                                           # 4網絡延遲  從數據庫中讀取內容須要消耗必定的時間.
        print("person%s 餘票:%s張"%(i,count_dic["count"]))     # 5.顯示用戶信息和查詢數據
def buy(i): #定義一個購票函數
    with open("db","r",encoding="utf-8")as f:         # 8.打開文件,讀取數據
        count_dic=json.load(f)                          # 9.反序列化獲得原數據
        if count_dic["count"]>0:                       # 10.判斷剩餘票數是否>0
            count_dic["count"]=count_dic["count"]-1   # 11.大於零則將原票數減1
            print("person%s購票成功"% i)              # 12顯示用戶購票成功
            time.sleep(0.2)                             # 13網絡延遲  (給數據庫傳遞新票務信息須要時間)
            with open("db","w",encoding="utf-8")as f: # 14打開文件
                json.dump(count_dic,f)                  # 15 將更改後的數據寫進數據庫

def task(i,lock): #定義一個任務函數
    search(i)                                           # 1 執行函數search ,將序號i傳給函數search
    lock.acquire()                                      # 6.用lock的acquire方法獲取這把鎖鑰匙    (buy函數被建立的鎖鎖住)
    buy(i)                                              # 7.執行函數buy()  並將參數i傳給函數
    lock.release()                                      # 16 用戶歸還鑰匙
if __name__=="__main__": #必須在這一步下面建立子進程
    lock=Lock()      #建立一個鎖lock
    for i in range(10):   #計數10如下
        p=Process(target=task,args=(i,lock))  #建立一個子進程,子進程對象是task,有兩個參數(一個是序號i,一個是加鎖)  須要建立十個子進程
        p.start()     #申請開啓一個子進程
應用:

 

 
    當多個進程共享一段數據的時候,數據會出現不安全的現象,須要加鎖來維護數據的安全性
注意:
from multiprocessing import Lock
lock=Lock()
lock.acquire()
print(111)
lock.release()
lock.acquire()    # 阻塞狀態  (只有一把鑰匙已經被獲取,且還沒有歸還)
print(222)    #不加只打印111
#解決辦法: 只須要在第二次獲取鑰匙前將鑰匙歸還即加上  lock.release()    加上lock.release()就能夠打印111,222

 


(二).信號量(Semaphore)
信號量的本質: 多把鑰匙對應一把鎖
lock+count計數
現象:
from multiprocessing import Process
from multiprocessing import Semaphore
sem=Semaphore(3)
sem.acquire()
print(1)
sem.acquire()
print(2)
sem.acquire()
print(3)
#sem.release()
sem.acquire()     #阻塞狀態    若是加sem.release()
print(4)          #不打印
案例:商場唱吧(KTV)
場景:四個小房子,十我的排隊等待進入房間
 import time    #導入時間模塊
    import random   #導入random模塊
    from multiprocessing import Process   #導入Process模塊
    from multiprocessing import Semaphore  #導入Semaphore信號量 模塊

    def ktv(num,sem):#定義一個函數ktv
        sem.acquire()                    # 1 獲取一把鑰匙     6 下一個用戶(進程)獲取鑰匙
        print("person%s進入ktv"% num)  # 2 顯示用戶信息及正在使用狀態
        time.sleep(random.randint(1,4))  # 3 使用時間段
        print("person%s離開ktv"% num)  # 4 顯示用戶離開
        sem.release()                    # 5 歸還鑰匙

    if __name__=="__main__":       #必須在這一條件下面建立新進程
        sem=Semaphore(4)             #可容許四人同時使用
        for i in range(10):         #計數  一共須要建立十個子進程
            p=Process(target=ktv,args=(i,sem)) # 建立一個子進程p 子進程對象爲ktv.須要兩個參數(序號,sem)
            p.start()                          # 申請開啓一個子進程 歸還鑰匙後,

 


(三).事件(Event)
方法:
等待: wait() 若是這個標誌是False 那麼就阻塞
若是這個標誌是True 那麼就非阻塞
查看標誌: is_set()
修改標誌:set()將標誌設置爲True
clear()將標誌設置爲False
 現象:
from multiprocessing import Event
e = Event()
print(e.is_set())    #False    在事件建立之初默認是False
e.set()               #將標誌設置爲True
print(e.is_set())    #True
e.wait()             #至關於什麼也沒作
e.clear()            #將標誌設置爲False
e.wait(timeout=10)    #阻塞10秒若是信號在阻塞10s以內變爲True,那麼不繼續阻塞直接pass,
#                     # 若是就阻塞10s以後狀態仍是沒變,那麼繼續,
# e.wait()能夠加參數  # 不管前面的wait的timeout是否經過,個人狀態都不會所以改變
print(e.is_set())    #False

 

紅綠燈模型:  控制交通燈的進程;
    import time
    import random
    from multiprocessing import Event
    from multiprocessing import Process

    def trafic_light(e):
        print("\033[1;31m紅燈亮\033[0m")   # 1 打印紅燈亮
        while True:                         #2無限循環
            time.sleep(2)                             #3睡兩秒
            # print(1,e.is_set())   #f
            if e.is_set():                            # 4.條件e.is_set()=False:阻塞
                print("\033[1;31m紅燈亮\033[0m")   #5.打印紅燈亮
                e.clear()                            #6.修改is_set()的狀態爲False
                # time.sleep(3)
                # print(2,e.is_set())   #f
            else:                                    #7.e.si_set==True若是目前狀態是True非阻塞
                print("\033[1;32m綠燈亮\033[0m")  #8.打印綠燈亮
                # print(4, e.is_set())    #f
                e.set()                              #9.設置is_set的狀態爲True 非阻塞(通行)
                # print(5,e.is_set())      #T

    def car(i,e):#車函數   (兩種狀況:等待,通行)
        # time.sleep(3)
        # print(3,e.is_set())     #True
        if not e.is_set():# 10.若是e.is_set()的狀態是True 則not e.is_set()爲False,如今狀態是阻塞,
            print("car%sd等待"% i)   #11.  #先提示用戶進入等待狀態
            e.wait()                 #12.   #直接pass
        print("car%s通行"% i)     #13.和條件判斷並行即條件不知足執行這一步
    if __name__=="__main__":
        e=Event()             #建立一個事件
        p=Process(target=trafic_light,args=(e,))   #建立一個進程對象爲trafic_light ,參數爲e
        p.start()     #申請開啓進程
        for i in range(10):
            p=Process(target=car,args=(i,e))  #建立十個car進程,參數爲i,e
            p.start()     #申請開啓進程
            time.sleep(random.randrange(0, 3, 2))    #要麼睡兩秒,要麼不睡.

 多進程解決tcp協議一個服務器與多個客戶端通訊矛盾python

服務器端代碼:數據庫

import socket
from multiprocessing import Process  #導入類Process
def talk(conn):      # 0 定義一個函數talk    6.執行talk進程
    try:
        while True:
            conn.send(b'alex')      #7.發送信息
            print(conn.recv(1024))   #8.接收信息
    finally:
        conn.close()

if __name__=="__main__":
    sk=socket.socket()           # 1 建立一個socket對象
    sk.bind(("127.0.0.1",9901)) # 2 綁定一個IP地址接口
    sk.listen()                  #3 監聽
    try:
        while True:
            conn,addr=sk.accept()    #4 無限循環可支持多個客戶端鏈接
            Process(target=talk,args=(conn,)).start() #5 鏈接之後須要開啓一個正常收發信息進程.進程對象就是talk
               #並向操做系統提出執行talk進程的申請.
    finally:
        sk.close()

客戶端代碼:json

import socket
import os
sk=socket.socket()
sk.connect(("127.0.0.1",9901))
while True:
    print(sk.recv(1024))
    sk.send(str(os.getpid()).encode('utf-8'))



sk.close()
相關文章
相關標籤/搜索