【问题标题】:Multithreaded wordcount and global dictionary update in PythonPython中的多线程字数和全局字典更新
【发布时间】:2017-04-12 10:34:48
【问题描述】:

在下面的代码中,目标是进行字数统计,add_counts函数作为线程并发调用,这个读取和更新的操作是线程安全的,这个answer说字典更新可能是线程安全的,但是读取和更新呢?更新如下:

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)

【问题讨论】:

    标签: python thread-safety


    【解决方案1】:

    读取和更新不是线程安全的——这里有一个示例,您可以尝试在本地使用以查看实际效果:

    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:锁

    You could require the threads to acquire a lock every time before they modify the dictionary. 这会稍微减慢程序的执行速度。

    解决方案 2:在最后对计数器求和

    根据您的具体用例,您可能能够为每个线程分配一个单独的计数器,并在线程完成计数后将计数相加。类似字典的collections.Counter 允许您轻松地将两个计数器添加在一起(这里是上面的示例修改为使用计数器):

    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'])
    

    【讨论】:

    • 在解决方案 1 中,我怎样才能使锁更细化而不是锁定整个字典?
    • 在第二种解决方案中,我使用的是 python 期货,因此无法控制传递多个计数器,因为无法控制线程
    • @stackit 我不确定是否有一种好的方法可以防止访问带有锁的字典键 - 如果有,希望其他人可以指出它。可能您可以通过维护线程本地 Counter 对象来组合两个建议的解决方案,并以适当的时间间隔锁定共享字典以从当前线程添加最新计数?
    • 是的,我就是这么想的
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-20
    • 2011-11-19
    • 1970-01-01
    • 1970-01-01
    • 2013-11-15
    • 1970-01-01
    相关资源
    最近更新 更多