kok*_*bir 11 django concurrency
当某个其他用户在update_object视图中处于活动状态时,我想在用户尝试删除对象时引发错误.我觉得需要某种类似互斥锁的机制.你有什么建议吗?
Dav*_*ger 14
所以,有一些方法可以做你所要求的.但是其中很多都不是独立于实现的:你可以使用锁或rlocks,但它们实际上只能在100%线程服务器上工作,而在fork/pre-fork实现中可能根本不工作.
这或多或少意味着锁定实现将取决于您.两个想法:
.lock 文件系统上的文件locked 模型类中的属性在这两种情况下,您都必须在更新时手动设置锁定对象,并在删除时检查它.尝试类似的东西:
def safe_update(request,model,id):
obj = model.objects.get(id)
if obj.locked:
raise SimultaneousUpdateError #Define this somewhere
else:
obj.lock()
return update_object(request,model,id)
# In models file
class SomeModel(models.Model):
locked = models.BooleanField(default = False)
def lock(self):
self.locked = True
super(models.Model,self).save()
def save(self):
# overriding save because you want to use generic views
# probably not the best idea to rework model code to accomodate view shortcuts
# but I like to give examples.
self.locked = False
# THIS CREATES A DIFFERENT CRITICAL REGION!
super(models.Model,self).save()
Run Code Online (Sandbox Code Playgroud)
这确实是一个笨拙的实现,你必须清理.您可能对创建不同的关键区域这一事实感到不舒服,但如果您将数据库用作实现而不使实现变得更复杂,我不会看到您将如何做得更好.(一种选择是使锁完全独立的对象.然后你可以在调用save()方法后更新它们.但是我不想编码那么.)如果你真的想使用基于文件的锁定系统,这也将解决问题.如果你是数据库命中偏执狂,这可能适合你.就像是:
class FileLock(object):
def __get__(self,obj):
return os.access(obj.__class__+"_"+obj.id+".lock",os.F_OK)
def __set__(self,obj,value):
if not isinstance(value,bool):
raise AttributeError
if value:
f = open(obj.__class__+"_"+obj.id+".lock")
f.close()
else:
os.remove(obj.__class__+"_"+obj.id+".lock")
def __delete__(self,obj):
raise AttributeError
class SomeModel(models.Model):
locked = FileLock()
def save(self):
super(models.Model,self).save()
self.locked = False
Run Code Online (Sandbox Code Playgroud)
无论如何,也许有一些方法可以根据您的口味混合和匹配这些建议?
由于添加了select_for_update,只要数据库支持,就可以通过一种简单的方法来获取对象的锁定.根据Django文档,postgresql,oracle和mysql至少支持它.
示例代码:
import time
from django.contrib.auth import get_user_model
from django.db import transaction
User = get_user_model()
target_user_pk = User.objects.all()[0].pk
with transaction.atomic():
print "Acquiring lock..."
to_lock = User.objects.filter(pk=target_user_pk).select_for_update()
# Important! Queryset evaluation required to actually acquire the lock.
locked = to_lock[0]
print locked
while True:
print "sleeping {}".format(time.time())
time.sleep(5)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
12022 次 |
| 最近记录: |