我正在编写一个简单的Python程序,使用asyncio.coroutines维护字典。设计是每个协程添加一个带有不同键的条目到字典。我的问题是,在修改字典时是否需要同步以避免竞争条件?换句话说,是写入字典原子?
这是我的计划:
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()
答案 0 :(得分:1)
是的 - 对字典的写作是原子的。 在asyncio模型中,即使它们不是线程安全的,除非你明确地在某处使用了线程池,否则没有“真正的并发” - 你的代码可能暂停的所有点都被“异步命令”很好地标记。
Python中采用的异步模型的巨大优势正是你获得了所有I / O绑定代码的并行性,而没有并行性的复杂性:await和其他命令是执行中唯一的执行点函数代码产生运行其他代码的权限 - 所以,即使你正在处理需要隔离的复杂数据结构,你所需要的只是将所有代码放在中间没有异步调用。
在您给出的示例中,update
代码永远不会被另一个协程中断,因为没有明确的暂停。你甚至可以添加一些逻辑来检查你是否没有覆盖由另一个协同例程写的相同的密钥,它仍然是好的(但对于多线程代码,你需要一个锁):
@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.')
但是,即使您的代码是多线程的,字典在Python中仍然是线程安全的。由于臭名昭着的全局解释器锁(GIL) - 几十年以来一直将Python保留在并行代码中 - 但权衡是数据结构(如字典和列表)的线程安全。
答案 1 :(得分:1)
不,你不需要担心锁定或竞争条件,因为asyncio
不使用线程。
协同程序提供的并发性都是在主线程中实现的。