Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Concurrent write to a dictionary using different keys in Python

I'm writing a simple Python program that maintains a dictionary using asyncio.coroutines. The design is that each coroutine add an entry with different keys to the dictionary. My question is that do I need synchronization when modifying the dictionary to avoid race condition? In other words, is write to a dictionary atomic?

Here is my program:

map ={}
key_set = Set(...)

@asyncio.coroutine
def update(key):
    # do I need synchronization here to avoid race condition?
    map[key] = ... # add a new entry with key to the map

fut = []
for key in key_set:
    fut.append(update(key))

loop = asyncio.get_event_loop()
loop.run_until_complete(
    asyncio.gather(*fut)
)
loop.close()
like image 242
M. Zheng Avatar asked Mar 10 '23 12:03

M. Zheng


1 Answers

Yes - writings to the dictionary are atomic. In an asyncio model, even if they were not threadsafe, unless you are explicitly using a threadpool somewhere, there is no "real concurrency" - all the points were your code may pause are well marked by an "async command".

The great advantage os the async model adopted in Python is exactly that you gain the equivalent of parallelism, for all I/O bound code, without the complexities of parallelism: the await and other commands are the only point in execution where your function code yield rights to other code to run - so, even if you were dealing with complex data structures that would need isolation, all you'd need is to put all the code for that with no async call in the middle.

In the example you give, the update code is never interrupted by another coroutine, as there is no explicit pause. You could even add some logic to check if you are not overwritting the same key written by another instance of the co-routine, and it would still be good (but for multi-threaded code, you'd need a lock for that):

@asyncio.coroutine
def update(key):
    if key not in map:
         map[key] = ... # add a new entry with key to the map
    else:
         logger.info(f'"{key}" already in use.')

But them, even if your code were multi-threaded, dictionaries are still thread safe in Python. Due to the infamous global interpreter lock (GIL) - which has otherwise held Python back in parallel code for decades - but the trade-off is exactly thread-safety of data structures like dictionaries and lists.

like image 118
jsbueno Avatar answered Apr 27 '23 18:04

jsbueno