如何处理 Django-Channels 消费者的竞争条件?
How to handle race condition on Django-Channels consumer?
我正在使用 django-channel 实现一项服务,我已经对我的问题做了一些解释,但您可以向下滚动到我提出问题的底部并忽略它们。
在此服务中,我使用异步缓存系统来提高服务的性能。
写入此缓存会引发竞争条件问题。
下面是这个缓存的两个主要功能
async def get_room_data_dict(self):
data = await self.cache_client.get(self.key)
return data
async def set_room_data_dict(self, room_data_dict):
is_success = await self.cache_client.set(self.key, room_data_dict)
return is_success
现在这个方法有问题了。
### coroutine 1 ###
room_data_dict = await cache_manager.get_room_data_dict()
# In the line below a context switch occurs and coroutine 2 continues to do some tasks
new_room_data_dict = await do_somthing(room_data_dict)
# coroutine 1 continue but room_data_dict is the old one and coroutine 1 going to save it so what coroutine 2 did is actually not applied
await cache_manager.set_room_data_dict(new_room_data_dict)
### coroutine 2 ###
# this coroutine continues without a context switch
room_data_dict = await cache_manager.get_room_data_dict()
new_room_data_dict = await do_somthing(room_data_dict)
await cache_manager.set_room_data_dict(new_room_data_dict)
# gets back to coroutine 1 and continues its code
现在,如果您仔细观察并接受了一些 OS 教育,您会发现协程 2 在 room_data_dict 上所做的更改实际上并未应用。
这是我为防止这个问题所做的事情,我会像下面这样更改函数
async def get_room_data_dict(self):
await self.room_data_dict_semaphore.acquire()
data = await self.cache_client.get(self.key)
return data
async def set_room_data_dict(self, room_data_dict):
is_success = await self.cache_client.set(self.key, room_data_dict)
self.room_data_dict_semaphore.release()
return is_success
当且仅当代码中的信号量在群组频道中共享时,此方法才能解决我的问题。
所以这是我要问的问题,如果你能回答其中的任何一个,我就能解决我的问题:
- 如何在两个协程之间共享一个对象的实例(在我的两个组通道之间的问题中)?
- 在 python 中,当您执行 an_instance.str() 时,您会得到一些显示实例内存地址的信息...我可以获取具有该地址的特定实例吗?
- 对于我的问题(使用信号量)以外的任何其他解决方案,我们将不胜感激。
acquire/release 外部作用域(协程 1)中的锁如何。
无论如何,各种锁定系统允许您使用字符串密钥来识别锁,因此它可以 acquired/released 来自不同的范围。你甚至可以使用像 python-redis-lock.
这样的分布式锁
我正在使用 django-channel 实现一项服务,我已经对我的问题做了一些解释,但您可以向下滚动到我提出问题的底部并忽略它们。
在此服务中,我使用异步缓存系统来提高服务的性能。 写入此缓存会引发竞争条件问题。 下面是这个缓存的两个主要功能
async def get_room_data_dict(self):
data = await self.cache_client.get(self.key)
return data
async def set_room_data_dict(self, room_data_dict):
is_success = await self.cache_client.set(self.key, room_data_dict)
return is_success
现在这个方法有问题了。
### coroutine 1 ###
room_data_dict = await cache_manager.get_room_data_dict()
# In the line below a context switch occurs and coroutine 2 continues to do some tasks
new_room_data_dict = await do_somthing(room_data_dict)
# coroutine 1 continue but room_data_dict is the old one and coroutine 1 going to save it so what coroutine 2 did is actually not applied
await cache_manager.set_room_data_dict(new_room_data_dict)
### coroutine 2 ###
# this coroutine continues without a context switch
room_data_dict = await cache_manager.get_room_data_dict()
new_room_data_dict = await do_somthing(room_data_dict)
await cache_manager.set_room_data_dict(new_room_data_dict)
# gets back to coroutine 1 and continues its code
现在,如果您仔细观察并接受了一些 OS 教育,您会发现协程 2 在 room_data_dict 上所做的更改实际上并未应用。
这是我为防止这个问题所做的事情,我会像下面这样更改函数
async def get_room_data_dict(self):
await self.room_data_dict_semaphore.acquire()
data = await self.cache_client.get(self.key)
return data
async def set_room_data_dict(self, room_data_dict):
is_success = await self.cache_client.set(self.key, room_data_dict)
self.room_data_dict_semaphore.release()
return is_success
当且仅当代码中的信号量在群组频道中共享时,此方法才能解决我的问题。
所以这是我要问的问题,如果你能回答其中的任何一个,我就能解决我的问题:
- 如何在两个协程之间共享一个对象的实例(在我的两个组通道之间的问题中)?
- 在 python 中,当您执行 an_instance.str() 时,您会得到一些显示实例内存地址的信息...我可以获取具有该地址的特定实例吗?
- 对于我的问题(使用信号量)以外的任何其他解决方案,我们将不胜感激。
acquire/release 外部作用域(协程 1)中的锁如何。
无论如何,各种锁定系统允许您使用字符串密钥来识别锁,因此它可以 acquired/released 来自不同的范围。你甚至可以使用像 python-redis-lock.
这样的分布式锁