Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/318.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python中的多线程字计数和全局字典更新_Python_Thread Safety - Fatal编程技术网

Python中的多线程字计数和全局字典更新

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

在以下代码中,目标是进行字数统计,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:
    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'])