第一階段:Python開發基礎 day37 進程的鎖和隊列以及生產消費模型

一,上節課內容回顧

'''
多道技術:
空間複用:多個程序公用一個內存條,彼此隔離,物理級別隔離
時間複用:公用一個cpu

切換的狀況:
    io切,佔用時間過長也切

串行:一個任務完完整整的運行結束,再運行下一個任務.
併發:看起來是同時執行多個任務     單核
並行:真正的作到了同時執行多個任務 多核



'''
###### 方式一
# from multiprocessing import Process
#
#
# def task():
#     pass
#
#
# if __name__ == '__main__':
#     p = Process(target=task)
#     p.start()
###### 方式二

# from multiprocessing import Process
#
# class MyP(Process):
#     def run(self):
#         pass
#
# if __name__ == '__main__':
#     p = MyP()
#     p.start() # 給操做系統發一個親請求,操做系統去開進程
#     print('sadf')
#

###### 申請一個空間,把父進程的代碼完整的copy一份放進去,而後去運行代碼.


###### join回顧
# from multiprocessing import Process
# import time,os
#
# def task(s):
#     time.sleep(s)
#
#
# if __name__ == '__main__':
#
#     p1 = Process(target=task,args=(100,))
#     # p2 = Process(target=task,args=(2,))
#     # p3 = Process(target=task,args=(3,))
#
#     p1.start()
#     # p2.start()
#     # p3.start()
#     # p1.join() # 等1s,
#     # p2.join() # 等1s,
#     # p3.join() # 等1s,內部會調用wait()
#     # print(p1.pid)
#     print('子',p1.pid)
#     print('主',os.getpid()) # 主進程要等待全部的子進程結束纔會結束.由於主進程要在結束前回收殭屍進程.(*****)

###### 殭屍進程. 沒有死透的子進程.
     # 孤兒進程,子進程運行的過程父進程死了就變成了孤兒進程,被進程init接管.

# 父進程一直不死,一直在開啓子進程,意味着佔用過過多的pid而且不回收.
# 解決方案: 強制殺死這個父進程.


##### 守護進程
# 本質也是個進程
# 主進程的代碼執行完畢守護進程直接結束。
# 大前提: 主進程結束以前守護進程一直運行着.
# from multiprocessing import Process
# import time
# def task():
#     print('守護進程  start')
#     # time.sleep(4)
#     print('守護進程  end')
#
#
# if __name__ == '__main__':
#     p = Process(target=task)
#     p.daemon = True
#     p.start()
#     time.sleep(2)
#     print('主')


# 進程鎖 (***)
#  進程鎖 是把鎖住的代碼變成了串行

# 隊列(*****)
#  主要掌握put 和 get

# 生產者消費者模型(*****)
# 本身敲一遍 重點掌握這種思想

#JoinableQueue(*)
# 看一下里面的守護進程.

# 初識線程(好好理解一下) (*****)

2、優化搶票

from  multiprocessing import Process,Lock
import json,time,os

def search():
    time.sleep(1) # 模擬網絡io
    with open('db.txt',mode='rt',encoding='utf-8') as f:
        res = json.load(f)
        print(f'還剩{res["count"]}')

def get():
    with open('db.txt',mode='rt',encoding='utf-8') as f:
        res = json.load(f)
        # print(f'還剩{res["count"]}')
    time.sleep(1) # 模擬網絡io
    if res['count'] > 0:
        res['count'] -= 1
        with open('db.txt',mode='wt',encoding='utf-8') as f:
            json.dump(res,f)
            print(f'進程{os.getpid()} 搶票成功')
        time.sleep(1.5) # 模擬網絡io
    else:
        print('票已經售空啦!!!!!!!!!!!')

def task(lock):
    search()

    # 鎖住
    lock.acquire()
    get()
    lock.release()
    # 釋放鎖頭

if __name__ == '__main__':
    lock = Lock() # 寫在主進程是爲了讓子進程拿到同一把鎖.
    for i in range(15):
        p = Process(target=task,args=(lock,))
        p.start()
        # p.join()

    #  進程鎖 是把鎖住的代碼變成了串行
    #  join 是把全部的子進程變成了串行


# 爲了保證數據的安全,串行犧牲掉效率.

2、隊列

# ipc機制 進程通信
# 管道:pipe 基於共享的內存空間
# 隊列:pipe+鎖 queue
from multiprocessing import Process,Queue

### 案例一
# q = Queue()
# q.put('魯照山')
# q.put([1,2,4])
# q.put(2)
# print(q.get())
# print(q.get())
# print(q.get())
# # q.put(5)
# # q.put(5)
# print(q.get()) # 默認就會一直等着拿值



### 案例2
# q = Queue(4)
# q.put('魯照山')
# q.put([1,2,4])
# q.put([1,2,4])
# q.put(2)
#
# q.put('喬碧蘿')  #隊列滿了的狀況再放值,會阻塞


### 案例3 (從這往下都是瞭解)
# q = Queue(3)
# q.put('zhao',block=True,timeout=2) #
# q.put('zhao',block=True,timeout=2) #
# q.put('zhao',block=True,timeout=2) #
#
# q.put('zhao',block=True,timeout=5) # put裏的  block=True 若是滿了會等待,timeout最多等待n s,若是ns仍是隊列仍是滿的就報錯了

### 案例4
# q = Queue()
# q.put('yyyy')
# q.get()
# q.get(block=True,timeout=5) # block=True 阻塞等待,timeout最多等5s, 剩下同上

### 案例5

# q = Queue(3)
# q.put('qwe')
# q.put('qwe')
# q.put('qwe')
#
# q.put('qwe',block=False) # 對於put來講block=False 若是隊列滿了就直接報錯

# q = Queue(3)
# q.put('qwe')
# q.get()
#
#
# q.get(block=False)
# block = Flase 拿不到不阻塞,直接報錯

### 案例6
q = Queue(1)
q.put('123')
# q.get()
q.put_nowait('666') # block = False
# q.get_nowait() # block = False
#

3、生產者消費者模型

'''
生產者: 生產數據的任務
消費者: 處理數據的任務

生產者--隊列(盆)-->消費者

生產者能夠不停的生產,達到了本身最大的生產效率,消費者能夠不停的消費,也達到了本身最大的消費效率.
生產者消費者模型大大提升了生產者生產的效率和消費者消費的效率.


# 補充: queue不適合傳大文件,通產傳一些消息.
'''

from multiprocessing import Process,Queue

def producer(q,name,food):
    '''生產者'''
    for i in range(10):
        print(f'{name}生產了{food}{i}')
        res = f'{food}{i}'
        q.put(res)
    q.put(None)

def consumer(q,name):
    '''消費者'''
    while True:
        res = q.get(timeout=5)
        if res is None:break
        print(f'{name}吃了{res}')

if __name__ == '__main__':
    q = Queue()
    p1 = Process(target=producer,args=(q,'rocky','包子'))
    c1 = Process(target=consumer,args=(q,'成哥'))
    p1.start()
    c1.start()

4、測試join ablequeue

from multiprocessing import Process,Queue,JoinableQueue


q = JoinableQueue()

q.put('zhao') # 放隊列裏一個任務
q.put('qian')

print(q.get())
q.task_done() # 完成了一次任務
print(q.get())
q.task_done() # 完成了一次任務
q.join() #計數器不爲0的時候 阻塞等待計數器爲0後經過

# 想象成一個計數器 :put +1   task_done -1

5、初步識別線程

'''
初識別線程.
在傳統操做系統中,每一個進程有一個地址空間,並且默認就有一個控制線程
在工廠中,  每一個車間都有房子,並且每一個車間默認就有一條流水線.

操做系統 ===> 工廠
進程 ===> 車間
線程 ===> 流水線
cpu  ===> 電源

線程:cpu最小的執行單位
進程:資源集合/資源單位.
線程運行 = 運行代碼
進程運行 = 各類資源 + 線程

'''
相關文章
相關標籤/搜索