考慮以下代碼段:
import concurrent.futures
import time
from random import random
class Test(object):
def __init__(self):
self.my_set = set()
def worker(self, name):
temp_set = set()
temp_set.add(name)
temp_set.add(name*10)
time.sleep(random() * 5)
temp_set.add(name*10 1)
self.my_set = self.my_set.union(temp_set) # question 1
return name
def start(self):
result = []
names = [1,2,3,4,5,6,7]
with concurrent.futures.ThreadPoolExecutor(max_workers=len(names)) as executor:
futures = [executor.submit(self.worker, x) for x in names]
for future in concurrent.futures.as_completed(futures):
result.append(future.result()) # question 2
是否有可能
self.my_set通過標有“問題 1”的行損壞?我相信union是原子的,但分配不是問題嗎?標有“問題 2”的那行有問題嗎?我相信這個串列
append是原子的,所以也許這沒關系。
我已經閱讀了這些檔案:
https://docs.python.org/3/library/stdtypes.html#set https://web.archive.org/web/20201101025814id_/http://effbot.org/zone/thread-synchronization.htm 是 Python變數賦值原子? https://docs.python.org/3/glossary.html#term-global-interpreter-lock
并執行了這個問題中提供的代碼片段,但我找不到在這種情況下并發應該如何作業的明確答案。
uj5u.com熱心網友回復:
關于問題 1:想想這里發生了什么:
self.my_set = self.my_set.union(temp_set)
有至少三個不同步驟的序列
- 該呼叫獲取(對物件的參考)
worker的副本self.my_setSet - 該
union函式構造一個新集合。 worker指派self.my_set新構造的集合。
那么如果兩個或多個工人同時嘗試做同樣的事情會發生什么呢?(注意:不能保證以這種方式發生,但可能會以這種方式發生。)
- 他們每個人都可以獲取對原始檔案的參考
my_set。 - 他們每個人都可以計算出一個新的集合,只由原始成員
my_set加上自己的貢獻組成。 - 他們每個人都可以將其新集合分配給
my_set變數。
問題出在第三步。如果它以這種方式發生,那么這些新集合中的每一個都只會包含創建它的一個工人的貢獻。不會有一個集合包含所有工人的新貢獻。當一切都結束時,my_set只會參考這些新集合中的一個——無論哪個執行緒是最后一個執行分配的執行緒都會“獲勝”——而其他新集合都將被丟棄。
防止這種情況的一種方法是使用互斥來阻止其他執行緒嘗試計算它們的新集合并同時更新共享變數:
class Test(object):
def __init__(self):
self.my_set = set()
self.my_set_mutex = threading.Lock()
def worker(self, name):
...
with self.my_set_mutex
self.my_set = self.my_set.union(temp_set)
return name
關于問題 2:附加到串列是否是“原子的”并不重要。該result變數是start方法的本地變數。在您顯示的代碼中,result除了創建它的執行緒之外,任何其他執行緒都無法訪問參考的串列。除非您與其他執行緒共享串列,否則執行緒之間不會有任何干擾。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/526395.html
上一篇:為什么并發放入ConcurrentHashMap不會產生預期的結果?
下一篇:在腳本中實作多執行緒/并行處理
