Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using a global dictionary with threads in Python

Is accessing/changing dictionary values thread-safe?

I have a global dictionary foo and multiple threads with ids id1, id2, ... , idn. Is it OK to access and change foo's values without allocating a lock for it if it's known that each thread will only work with its id-related value, say thread with id1 will only work with foo[id1]?

like image 613
Alex Avatar asked Aug 21 '09 14:08

Alex


People also ask

Is dictionary in Python thread-safe?

Python's built-in structures are thread-safe for single operations, but it can sometimes be hard to see where a statement really becomes multiple operations. Your code should be safe.

How is Python thread-safe?

If a class or a program has immutable state then the class is necessarily thread-safe. Similarly, the shared state in an application where the same thread mutates the state using an operation that translates into an atomic bytecode instruction can be safely read by multiple reader threads.

How do you lock a thread in Python?

A lock can be locked using the acquire() method. Once a thread has acquired the lock, all subsequent attempts to acquire the lock are blocked until it is released. The lock can be released using the release() method.

How is Python thread implemented?

Use the Python threading module to create a multi-threaded application. Use the Thread(function, args) to create a new thread. Call the start() method of the Thread class to start the thread. Call the join() method of the Thread class to wait for the thread to complete in the main thread.


1 Answers

Assuming CPython: Yes and no. It is actually safe to fetch/store values from a shared dictionary in the sense that multiple concurrent read/write requests won't corrupt the dictionary. This is due to the global interpreter lock ("GIL") maintained by the implementation. That is:

Thread A running:

a = global_dict["foo"] 

Thread B running:

global_dict["bar"] = "hello" 

Thread C running:

global_dict["baz"] = "world" 

won't corrupt the dictionary, even if all three access attempts happen at the "same" time. The interpreter will serialize them in some undefined way.

However, the results of the following sequence is undefined:

Thread A:

if "foo" not in global_dict:    global_dict["foo"] = 1 

Thread B:

global_dict["foo"] = 2 

as the test/set in thread A is not atomic ("time-of-check/time-of-use" race condition). So, it is generally best, if you lock things:

from threading import RLock  lock = RLock()  def thread_A():     with lock:         if "foo" not in global_dict:             global_dict["foo"] = 1  def thread_B():     with lock:         global_dict["foo"] = 2 
like image 156
Dirk Avatar answered Sep 23 '22 03:09

Dirk