Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to make a thread-safe global counter in python

I'm creating a threading.Timer(2,work) run threads. Inside each work function, upon some condition the global counter must increment without conflict for access of counter variable among the spawned work threads.

I've tried Queue.Queue assigned counter as well as threading.Lock(). Which is a best way to implement thread-safe global increment variable.

Previously someone asked question here: Python threading. How do I lock a thread?

like image 895
L.fole Avatar asked Jan 29 '16 15:01

L.fole


Video Answer


2 Answers

Not sure if you have tried this specific syntax already, but for me this has always worked well:

Define a global lock:

import threading
threadLock = threading.Lock()

and then you have to acquire and release the lock every time you increase your counter in your individual threads:

with threadLock:
    global_counter += 1
like image 137
mommermi Avatar answered Oct 21 '22 09:10

mommermi


One solution is to protect the counter with a multiprocessing.Lock. You could keep it in a class, like so:

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())

The above snippet was first taken from Eli Bendersky's blog, here.

like image 36
Michael Foukarakis Avatar answered Oct 21 '22 08:10

Michael Foukarakis