gpt4 book ai didi

python - 在 model.save() 中处理竞争条件

转载 作者:太空狗 更新时间:2023-10-29 16:56:41 24 4
gpt4 key购买 nike

应该如何处理模型的 save() 方法中可能出现的竞争条件?

例如,以下示例实现了一个模型,其中包含相关项的有序列表。创建新项目时,当前列表大小用作其位置。

据我所知,如果同时创建多个项目,这可能会出错。

class OrderedList(models.Model):
# ....
@property
def item_count(self):
return self.item_set.count()

class Item(models.Model):
# ...
name = models.CharField(max_length=100)
parent = models.ForeignKey(OrderedList)
position = models.IntegerField()
class Meta:
unique_together = (('parent','position'), ('parent', 'name'))

def save(self, *args, **kwargs):
if not self.id:
# use item count as next position number
self.position = parent.item_count
super(Item, self).save(*args, **kwargs)

我遇到了 @transactions .commit_on_success() 但这似乎只适用于 View 。即使它确实适用于模型方法,我仍然不知道如何正确处理失败的事务。

我目前正在这样处理它,但感觉更像是一种 hack 而不是解决方案

def save(self, *args, **kwargs):
while not self.id:
try:
self.position = self.parent.item_count
super(Item, self).save(*args, **kwargs)
except IntegrityError:
# chill out, then try again
time.sleep(0.5)

有什么建议吗?

更新:

上述解决方案的另一个问题是,如果 IntegrityError 是由 name 冲突(或任何其他独特的领域)。

为了记录,这是我目前所拥有的,似乎可以满足我的需要:

def save(self, *args, **kwargs):   
# for object update, do the usual save
if self.id:
super(Step, self).save(*args, **kwargs)
return

# for object creation, assign a unique position
while not self.id:
try:
self.position = self.parent.item_count
super(Step, self).save(*args, **kwargs)
except IntegrityError:
try:
rival = self.parent.item_set.get(position=self.position)
except ObjectDoesNotExist: # not a conflict on "position"
raise IntegrityError
else:
sleep(random.uniform(0.5, 1)) # chill out, then try again

最佳答案

它可能感觉对你来说像是一个 hack,但对我来说它看起来像是“乐观并发”方法的合法、合理的实现——尝试做任何事情,检测由竞争条件引起的冲突,如果发生,请稍后重试。一些数据库系统地使用它而不是锁定,并且它可以带来更好的性能,除非在 很多 写入负载的系统下(这在现实生活中很少见)。

我非常喜欢它,因为我将其视为 Hopper 原则的一般情况:“请求宽恕比请求许可更容易”,它在编程中广泛应用(尤其是但不限于 Python——Hopper 语言通常是毕竟,功劳在于 Cobol;-)。

我建议的一项改进是等待一段随机时间——避免“元竞争条件”,即两个进程同时尝试,都发现冲突,然后都重试再次同时发生,导致“饥饿”。 time.sleep(random.uniform(0.1, 0.6)) 等就足够了。

更精细的改进是在遇到更多冲突时延长预期的等待时间——这就是 TCP/IP 中所谓的“指数退避”(您不必以指数方式延长时间,即通过常数乘数当然,每次 > 1,但这种方法具有良好的数学特性)。它只保证限制非常写入加载系统的问题(在尝试写入过程中经常发生多次冲突)并且在您的特定情况下可能不值得这样做。

关于python - 在 model.save() 中处理竞争条件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3522827/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com