1. 程式人生 > 實用技巧 >併發程式設計之守護程序、互斥鎖以及佇列等相關內容-37

併發程式設計之守護程序、互斥鎖以及佇列等相關內容-37

1.回顧

···建立程序的兩種方式

····第一種
from multiprocessing import Process
import time


def task(n):
print('我是子程序')
time.sleep(n)
print('子程序結束')


if __name__ == '__main__':
# args=(), kwargs={}
# t=Process(task,args=(1,))
t = Process(target=task, kwargs={'n': 1})
t.start() # 通知作業系統,開啟程序,執行task函式
print('主')

····第二種:
from multiprocessing import Process
import time

class Task(Process):
def __init__(self, n):
super().__init__()
self.n = n

def run(self):
print('我是子程序')
time.sleep(self.n)
print('子程序結束')


if __name__ == '__main__':
t = Task(1)
# t.run(1) # 不是呼叫t.run(),而是呼叫t.start()
t.start()
print('主')


···join的使用
from multiprocessing import Process
import time


def task(n):
print('我是子程序')
time.sleep(n)
print('子程序結束')


if __name__ == '__main__':
ctime = time.time()
t = Process(target=task, kwargs={'n': 1})
t2 = Process(target=task, kwargs={'n': 2})
t.start()
t2.start()
t.join() # 等待t子程序執行完成
t2.join() # 等待t2子程序執行完成
print('主')
ctime2 = time.time()
print(ctime2 - ctime)


···程序之間資料隔離
from multiprocessing import Process
import time

age = 18


def task(n):
global age # 區域性修改全域性
age = 99
print('我是子程序')
time.sleep(n)
print('子程序結束')
print(age)


if __name__ == '__main__':
t = Process(target=task, kwargs={'n': 1})
t.start()
t.join() # 等待t子程序執行完成
print('主')
print(age) # 資料沒有變,主程序中列印age和子程序的age沒有半毛錢關係,資料是隔離的

2.程序的其他方法

from multiprocessing import Process,current_process
import time
import os

# 每個程序都會有自己的id號pid

def task():
print('子程序')

# 當前程序的id號
print(current_process().pid)
print(os.getpid()) # 跟上面打印出來是一模一樣的
# 取出該程序父id號
print('-----',os.getppid())
# current_process()當前程序物件

print(current_process().is_alive())
time.sleep(2)

print('子程序結束')


if __name__ == '__main__':
t = Process(target=task, )
t.start()
# t1 = Process(target=task, )
# t1.start()
# t.is_alive() # t這個程序是否存活
# print('主程序列印的結果',t.is_alive())
print(t.pid)
time.sleep(0.5)
# t.terminate() # 把t程序關閉
# time.sleep(0.1)
print('主程序列印的結果', t.is_alive())

3.守護程序

from multiprocessing import Process, current_process
import time
import os


def task():
# print(os.getpid())
print('子程序')
time.sleep(200)
print('子程序結束')


if __name__ == '__main__':
t = Process(target=task, )
# 守護程序:主程序一旦結束,子程序也結束
# t.daemon=True # 一定要加在啟動之前
t.start()

time.sleep(1)
print('主程序結束')
print(os.getppid())
time.sleep(100)

#守護程序是隨著主程序的程式碼結束而結束的,注意只是程式碼跑完,守護程序就結束
# 問題1 :主程序的父程序是誰?就是pycharm
# 問題2 :主程序開了很多子程序,每個都需要設定守護嗎?看你的需求,你想讓某個程序是守護:t.daemon=True

4.互斥鎖

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


def search():
# 查票的函式
# 開啟檔案,讀出ticket_count
with open('ticket', 'r', encoding='utf-8') as f:
dic = json.load(f)
print('餘票還有:', dic.get('ticket_count'))


def buy():
with open('ticket', 'r', encoding='utf-8') as f:
dic = json.load(f)

time.sleep(random.randint(1, 3)) # 模擬一下網路延遲
if dic.get('ticket_count') > 0:
# 能夠買票
dic['ticket_count'] -= 1
# 儲存到檔案中去
with open('ticket', 'w', encoding='utf-8') as f:
json.dump(dic, f)
print('買票成功')
else:
# 買票失敗
print('買票失敗')


# 寫一個函式,先查票,再買票

def task(mutex):
search()
# 買票過程要加鎖
# 買前加鎖
# mutex.acquire()
# buy() # 10個程序變成了序列執行
# # 買後釋放鎖
# mutex.release()
with mutex:
buy()


if __name__ == '__main__':
# 鎖的建立,在哪?主程序建立鎖
mutex = Lock() # 建立一把鎖
# 模擬十個人買票(開10個程序)
for i in range(10):
t = Process(target=task, args=(mutex,))
t.start()

# 面向物件高階:魔法方法(__開頭的),__enter__和__exit__,上下文管理器
# 自己寫一個類,實現類似於開啟檔案 with open 的功能
# with MyClass('檔名','方式','編碼') as f:
# f.read()


#在這寫程式碼,f就關閉了


# class MyClass():
# def __init__(self,file_name,mode,encoding):
# self.file_name=file_name
# self.mode=mode
# self.encoding=encoding
#
# def __enter__(self):
# print('只要有with,就會執行我')
# self.file=open(self.file_name,self.mode,encoding=self.encoding)
#
# return self.file
#
# def __exit__(self, exc_type, exc_val, exc_tb):
# # 只要頂格寫程式碼,就會執行我
# print('只要頂格寫程式碼,就會執行我')
# self.file.close()
#
#
# with MyClass('ticket','r','utf-8') as f:
# print(f.read())
# print('xxss')
# print("sdfadasf")
#
#
# # a=MyClass('ticket','r','utf-8')
#

5.佇列



from multiprocessing import Queue

# 例項化得到要給物件

q=Queue(5) # 預設很大,可以放很多,寫了個5,只能放5個

# 往管道中放值
q.put(1)
q.put('lqz')
q.put(18)
q.put(19)
# q.put(20)
# q.put(21)
# q.put_nowait(100)

# 從管道中取值
# print(q.get())
# print(q.get())
# print(q.get())
# print(q.get(timeout=100)) # 等0.1s還沒有值,就結束
# print(q.get_nowait()) # 不等了,有就是有,沒有就沒有

print(q.empty()) # 看一下佇列是不是空的
print(q.full()) # 看一下佇列是不是滿的


# 總結:
'''
q=Queue(佇列大小)
# 放值
q.put(asdf)
q.put_nowait(asdf) # 佇列滿了,放不進去就不放了,報錯

# 取值
q.get() # 從佇列頭部取出一個值
q.get_nowait() # 從佇列頭部取值,沒有就拋錯


# 佇列是否為空,是否滿
print(q.empty()) # 看一下佇列是不是空的
print(q.full()) # 看一下佇列是不是滿的
'''

6.程序間通訊--IPC機制

from multiprocessing import Process, current_process, Queue
import time
import os


def task1(q):
print('我是task1程序,我的id號是:%s'%os.getpid())
q.put('lqz is handsome')


def task2(q):

# res=q.get()
# print('我是task2程序,我的id號是:%s'%os.getpid(),res)
print('我是task2程序,我的id號是:%s'%os.getpid())


if __name__ == '__main__':
q = Queue(5)

t1 = Process(target=task1, args=(q,))
t1.start()
t2 = Process(target=task2, args=(q,))
t2.start()

print(q.get())