簡體   English   中英

如何在 python 中創建一個線程安全的全局計數器

[英]how to make a thread-safe global counter in python

我正在創建一個threading.Timer(2,work)運行線程。 在每個工作 function 中,在某些情況下,全局計數器必須在沒有沖突的情況下遞增,以便在生成的工作線程中訪問計數器變量。

我試過Queue.Queue分配的計數器以及threading.Lock() 這是實現線程安全的全局增量變量的最佳方式。

之前有人在這里提問: Python線程。 如何鎖定線程?

不確定你是否已經嘗試過這種特定的語法,但對我來說這一直都很好用:

定義全局鎖:

import threading
threadLock = threading.Lock()

然后,每次增加單個線程中的計數器時,您必須獲取並釋放鎖定:

with threadLock:
    global_counter += 1

最簡單的解決方案是使用multiprocessing.Lock保護計數器。 multiprocessing.Lock 我喜歡將它保存在一個類中,如下所示:

from multiprocessing import Process, RawValue, Lock
import time

class Counter(object):
    def __init__(self, value=0):
        # RawValue because we don't need it to create a Lock:
        self.val = RawValue('i', value)
        self.lock = Lock()

    def increment(self):
        with self.lock:
            self.val.value += 1

    def value(self):
        with self.lock:
            return self.val.value

def inc(counter):
    for i in range(1000):
        counter.increment()

if __name__ == '__main__':
    thread_safe_counter = Counter(0)
    procs = [Process(target=inc, args=(thread_safe_counter,)) for i in range(100)]

    for p in procs: p.start()
    for p in procs: p.join()

    print (thread_safe_counter.value())

上面的代碼中首先從禮Bendersky的博客采取這里

如果您使用的是 CPython 1 ,則無需顯式鎖定即可執行此操作:

import itertools

class Counter:
    def __init__(self):
        self._incs = itertools.count()
        self._accesses = itertools.count()

    def increment(self):
        next(self._incs)

    def value(self):
        return next(self._incs) - next(self._accesses)

my_global_counter = Counter()

我們需要兩個計數器:一個用於計算增量,一個用於計算value()的訪問次數。 這是因為itertools.count不提供訪問當前值的方法,只提供下一個值。 因此,我們需要通過詢問值來“撤消”我們招致的增量。

這是線程安全的,因為itertools.count.__next__()在 CPython 中是原子的(感謝 GIL。)並且我們不會保留差異。

請注意,如果並行訪問value() ,則確切的數字可能不會完全穩定或嚴格單調遞增。 它可以加上或減去與訪問的線程數成比例的余量。 理論上, self._incs可以先在一個線程中更新,而self._accesses可以先在另一個線程中更新。 但總的來說,系統永遠不會因為無人看守的寫入而丟失任何數據; 它總是會穩定到正確的值。

1並非所有 Python 都是 CPython,但很多(大多數?)是。

2感謝 https://julien.danjou.info/atomic-lock-free-counters-in-python/最初的想法是使用itertools.count來遞增並使用第二個訪問計數器來更正。 他們幾乎沒有打開所有的鎖就停下了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM