目錄
- 一、進程同步
- 二、為什么需要進程同步
- 三、Python中實現進程同步
-
四、多進程模擬同時搶票
- 4.1 通過鎖控制進程資源訪問
- 總結
盡管并發編程讓我們能更加充分的利用IO資源,但是也給我們帶來了新的問題: 當多個進程使用同一份數據資源的時候,就會引發數據安全或順序混亂問題。
一、進程同步
多個進程同時執行,為了相互制約各進程對資源的訪問,使得各個進程的執行相互同步。
在我的理解里,進程同步也算是進程間通訊(ipc)的一種手段。
二、為什么需要進程同步
多進程會引發搶占資源的問題,為了解決這個問題就需要各進程之間相互同步,控制進程對關鍵資源的訪問。
在C語言中實現進程同步的方式有很多,比如:信號量,鎖機制等。
例子: 演示多進程資源搶占問題
import os
import time
import random
from multiprocessing import Process
def work(n):
print('%s: %s is running' %(n,os.getpid()))
time.sleep(random.random())
print('%s:%s is done' %(n,os.getpid()))
if __name__ == '__main__':
for i in range(3):
p=Process(target=work,args=(i,))
p.start()
三、Python中實現進程同步
-
首先
from multiprocessing import Lock
-
在主進程中,實例化得到鎖,
lock = Lock()
,并傳給子進程 -
在子進程中通過上鎖和解鎖實現對多進程對資源的控制。
lock.acquire()
上鎖,lock.release()
解鎖
演示:通過Python鎖機制控制資源的訪問
def work(lock,n):
print(f"等待開鎖 進程{n}")
# 上鎖
lock.acquire() # 當上鎖之后別的進程無法訪問,會阻塞住
print(f'進程{n} pid: %s is running' % ( os.getpid()))
time.sleep(random.random())
print(f'進程{n} pid: %s is done' % (os.getpid()))
# 開鎖
lock.release()
if __name__ == '__main__':
lock=Lock() # 實例化得到鎖
for i in range(3):
p=Process(target=work,args=(lock,i))
p.start()
等待開鎖 進程1
進程1 pid: 8696 is running
等待開鎖 進程0
等待開鎖 進程2
進程1 pid: 8696 is done
進程0 pid: 14264 is running
進程0 pid: 14264 is done
進程2 pid: 22724 is running
進程2 pid: 22724 is done
根據結果可以發現,在上鎖之前的代碼。多進程是并發訪問的,但上鎖之后,直到解鎖后才能有第二個人訪問。以此類推。 就好像上廁所排隊一樣,進去一個人關上門鎖上,第二個人等著。
但是看完你會有個疑問,那被鎖上的代碼,每個進程在訪問的時候不就是串行的依次在訪問嘛。
確實,鎖機制 保證了數據的安全,但犧牲掉效率.
四、多進程模擬同時搶票
# 文件db的內容為:{"count":1}
# 注意一定要用雙引號,不然json無法識別
# 并發運行,效率高,但競爭寫同一文件,數據寫入錯亂
from multiprocessing import Process,Lock
import time,json,random
def search():
dic=json.load(open('db'))
print('剩余票數%s' %dic['count'])
def get():
dic=json.load(open('db'))
time.sleep(0.1) # 模擬讀數據的網絡延遲
if dic['count'] >0:
dic['count']-=1
time.sleep(0.2) # 模擬寫數據的網絡延遲
json.dump(dic,open('db','w'))
print('購票成功')
def task():
search()
get()
if __name__ == '__main__':
for i in range(100): # 模擬并發100個客戶端搶票
p=Process(target=task)
p.start()
上述代碼,你會發現多個進程在同時搶票,相互搶占文件資源,每個進程都把文件讀入到內存中進行搶票。實際上,資源只能被一個人占有,這就會引發問題
4.1 通過鎖控制進程資源訪問
def search():
time.sleep(1)
with open("db","w",encoding="utf8") as f:
data = json.load(f)
print(f'還剩{data["count"]}')
def get():
with open('db','rt',encoding='utf-8') as f:
res = json.load(f)
time.sleep(1) # 模擬網絡io
if res['count'] > 0:
res['count'] -= 1
with open('db', 'w', encoding='utf-8') as f:
json.dump(res, f)
print(f'進程{os.getpid()} 搶票成功')
time.sleep(1.5) # 模擬網絡io
else:
print('票已經售空啦!!!!!!!!!!!')
def task(lock):
print(f"進程:{os.getpid()} 正在搶票中。。。")
# 上鎖 每個進程都會訪問一遍,所以加鎖就等于上鎖到解鎖這段代碼是串行的
lock.acquire() # 當上鎖之后別的進程無法訪問,會阻塞住
get()
# 開鎖
lock.release()
if __name__ == '__main__':
# 創建鎖
lock = Lock()
pro_list = []
# 創建進程
for i in range(10):
p = Process(target=task, args=(lock,))
p.start()
pro_list.append(p)
# 回收進程
for i in range(10):
pro_list[i].join()
總結
進程同步理論上應該是進程間通訊中的一部分,是一個大話題,每個語言也都有實現進程同步的需求。需要將各個進程對資源的訪問加以限制。在各個語言中也都有限制。這里目前只介紹了這一種進程同步的方法。
鎖機制 是把鎖住的代碼變成了串行,保證了數據的安全,但犧牲掉效率.
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
