Python中的多线程字计数和全局字典更新
在以下代码中,目标是进行字数统计,add_counts函数作为线程同时调用,这是读取和更新threadsafe的操作吗,这表示字典更新可能是threadsafe的,但如何读取和更新,如下所示:Python中的多线程字计数和全局字典更新,python,thread-safety,Python,Thread Safety,在以下代码中,目标是进行字数统计,add_counts函数作为线程同时调用,这是读取和更新threadsafe的操作吗,这表示字典更新可能是threadsafe的,但如何读取和更新,如下所示: word_counts={} @concurrent def add_counts(line): for w in line.split(): word_counts[w] = word_counts.get(w, 0) + 1 for line in somebigfile
word_counts={}
@concurrent
def add_counts(line):
for w in line.split():
word_counts[w] = word_counts.get(w, 0) + 1
for line in somebigfile:
add_counts(line)
阅读和更新不是线程安全的-这里有一个示例,您可以尝试在本地使用,以查看实际效果:
from threading import Thread
def add_to_counter(ctr):
for i in range(100000):
ctr['ctr'] = ctr.get('ctr', 0) + 1
ctr = {}
t1 = Thread(target=add_to_counter, args=(ctr,))
t2 = Thread(target=add_to_counter, args=(ctr,))
t1.start()
t2.start()
t1.join()
t2.join()
print(ctr['ctr'])
结果显然取决于调度和其他系统/定时相关的细节,但在我的系统中,我总是在200000
下得到不同的数字
解决方案1:锁
这会稍微降低程序的执行速度
解决方案2:在末尾对计数器求和
根据具体的用例,您可能能够为每个线程分配一个单独的计数器,并在线程完成计数后将计数相加。类字典允许您轻松地将两个计数器添加到一起(下面是上面修改为使用计数器的示例):
在解决方案1中,如何使锁更细粒度,而不是锁定整个dict?在第二个解决方案中,我使用python futures,因此无法控制传递多个计数器,因为无法控制threads@stackit我不确定是否有一种好方法可以防止使用锁访问一个字典密钥–如果有,希望其他人能给你指点一下。可能您可以通过维护线程本地
计数器
对象,并在适当的时间间隔锁定共享字典,将当前线程的最新计数添加到共享字典中,来组合这两种建议的解决方案?是的,这就是我刚才的想法
from collections import Counter
from threading import Thread
def add_to_counter(counter):
for i in range(100000):
counter['ctr'] = counter.get('ctr', 0) + 1
ctr1 = Counter()
ctr2 = Counter()
t1 = Thread(target=add_to_counter, args=(ctr1,))
t2 = Thread(target=add_to_counter, args=(ctr2,))
t1.start()
t2.start()
t1.join()
t2.join()
ctr = ctr1 + ctr2
print(ctr['ctr'])