python multiprocessing多進程變量共享與加鎖的實現(xiàn)
python多進程和多線程是大家會重點了解的部分,因為很多工作如果并沒有前后相互依賴關(guān)系的話其實順序并不是非常的重要,采用順序執(zhí)行的話就必定會造成無謂的等待,任憑cpu和內(nèi)存白白浪費,這是我們不想看到的。
為了解決這個問題,我們就可以采用多線程或者多進程的方式,(多線程我們之后再講),而這兩者之間是有本質(zhì)區(qū)別的。就內(nèi)存而言,已知進程是在執(zhí)行過程中有獨立的內(nèi)存單元的,而多個線程是共享內(nèi)存的,這是多進程和多線程的一大區(qū)別。
利用Value在不同進程中同步變量
在多進程中,由于進程之間內(nèi)存相互是隔離的,所以無法在多個進程中用直接讀取的方式共享變量,這時候就可以用multiprocessing庫中的 Value在各自隔離的進程中共享變量。
下面是一個多進程的例子:
假設(shè)有一個counter用來記錄程序經(jīng)過的總循環(huán)次數(shù),每調(diào)用一次count函數(shù)之后counter就會增加20,在主程序中用循環(huán)開10個進程分別調(diào)用count函數(shù),那么理想狀態(tài)下,在十個進程中共享的counter值到程序結(jié)束后應(yīng)該是200。
from multiprocessing import Process, Value
import time
def count(v):
for i in range(20):
time.sleep(0.01)
v.value += 1
def main():
value = Value('i',0)
processes = [Process(target=count, args=(value,)) for i in range(10)]
for p in processes:
p.start()
for p in processes:
p.join()
print(value.value)
if __name__ == '__main__':
for i in range(10):
main()
運行這個例子,會得到怎樣的結(jié)果呢?
188
180
168
186
183
179
186
181
166
186
我在主程序里運行了十次這個程序,而最后的結(jié)果是160-180之間,總之,沒有一次到200。這是什么原因呢?
相信很多人都已經(jīng)明白了問題所在,那就是因為在multiprocessing庫中的Value是細(xì)粒度的,Value中有一個ctypes類型的對象,擁有一個value屬性來表征內(nèi)存中實際的對象。Value可以保證同時只有一個單獨的線程或進程在讀或者寫value值。這么看起來沒有什么問題。
然而在第一個進程加載value值的時候,程序卻不能阻止第二個進程加載舊的值。兩個進程都會把value拷貝到自己的私有內(nèi)存然后進行處理,并寫回到共享值里。
那么這么會出現(xiàn)什么問題呢?
最后的共享值只接收到了一次值的增加,而非兩次。
利用Lock在不同進程共享變量時加鎖
上面的問題其實可以用一個非常簡單的方法解決,我們只需要調(diào)用multiprocessing庫中的Lock (鎖)就可以保證一次只能有一個進程訪問這個共享變量。修改后的代碼如下:
from multiprocessing import Process, Value, Lock
from time import sleep
def count(x,lock):
for i in range(20):
sleep(0.01)
with lock:
x.value += 1
def main():
counter = Value('i',0)
lock = Lock()
processes = [Process(target=count,args=(counter,lock)) for i in range(10)]
for p in processes:
p.start()
for p in processes:
p.join()
print(counter.value)
if __name__ == '__main__':
for i in range(10):
main()
這樣一來,輸出的結(jié)果就會恒定為200了。
一些補充
1. 調(diào)用get_lock() 函數(shù)
其實Value這個包里已經(jīng)包含了鎖的概念,如果調(diào)用get_lock() 函數(shù)就可以自動給共享變量加鎖。這樣其實是比較推薦的方式,因為這樣就不需要同時調(diào)用兩個包。修改如下:
from multiprocessing import Process, Value
from time import sleep
def count(x):
for i in range(20):
global counter # 聲明全局變量
sleep(0.01)
with counter.get_lock(): # 直接調(diào)用get_lock()函數(shù)獲取鎖
x.value += 1
def main():
processes = [Process(target=count, args=(counter,)) for i in range(10)]
for p in processes:
p.start()
for p in processes:
p.join()
print(counter.value)
if __name__ == '__main__':
counter = Value('i', 0) # 需要把全局變量移到主程序
main()
上面的程序更加明確,且最終結(jié)果也是200。
2. 使用 multiprocessing.RawValue
整個multiprocessing包里剛剛調(diào)用的Value和Lock還可以統(tǒng)一被 multiprocessing.RawValue取代。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Python多進程并發(fā)(multiprocessing)用法實例詳解
- Python3多進程 multiprocessing 模塊實例詳解
- Python多進程multiprocessing用法實例分析
- Python標(biāo)準(zhǔn)庫之多進程(multiprocessing包)介紹
- python基于multiprocessing的多進程創(chuàng)建方法
- python multiprocessing 多進程并行計算的操作
- 簡單學(xué)習(xí)Python多進程Multiprocessing
- Python使用multiprocessing實現(xiàn)多進程的詳細(xì)步驟記錄
相關(guān)文章
Python要求O(n)復(fù)雜度求無序列表中第K的大元素實例
這篇文章主要介紹了Python要求O(n)復(fù)雜度求無序列表中第K的大元素實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-04-04
python通過裝飾器檢查函數(shù)參數(shù)數(shù)據(jù)類型的方法
這篇文章主要介紹了python通過裝飾器檢查函數(shù)參數(shù)數(shù)據(jù)類型的方法,涉及Python裝飾器的使用技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-03-03
python神經(jīng)網(wǎng)絡(luò)學(xué)習(xí)數(shù)據(jù)增強及預(yù)處理示例詳解
這篇文章主要為大家介紹了python神經(jīng)網(wǎng)絡(luò)學(xué)習(xí)數(shù)據(jù)增強及預(yù)處理示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-05-05
Python使用socket模塊實現(xiàn)簡單tcp通信
這篇文章主要介紹了Python使用socket模塊實現(xiàn)簡單tcp通信,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-08-08
Python使用ntplib庫同步校準(zhǔn)當(dāng)?shù)貢r間的方法

