我找不到一个很好的方法来锁定Django中的一个关键部分。我可以使用锁或信号量,但python实现仅用于线程,因此如果生产服务器分叉那么那些将不会被尊重。有没有人知道一种方式(我现在正在考虑posix信号量)以保证跨进程的锁定,或者禁止这种方式阻止Django服务器分叉。
答案 0 :(得分:16)
如果使用RDBMS,则可以使用其“LOCK”机制。 例如,当一个“SELECT FOR UPDATE”事务锁定一行时,另一个“SELECT FOR UPDATE”事务必须等待。
# You can use any Python DB API.
[SQL] BEGIN;
[SQL] SELECT col_name FROM table_name where id = 1 FOR UPDATE;
[Process some python code]
[SQL] COMMIT;
答案 1 :(得分:13)
使用Django内置的select_for_update函数。
https://docs.djangoproject.com/en/1.8/ref/models/querysets/#select-for-update
来自文档:
返回一个查询集,该查询集将锁定行直到事务结束,在支持的数据库上生成SELECT ... FOR UPDATE SQL语句。
例如:
entries = Entry.objects.select_for_update().filter(author=request.user)
所有匹配的条目将被锁定,直到事务块结束,这意味着将阻止其他事务更改或获取锁定。
答案 2 :(得分:9)
在您的应用突然需要在多个服务上运行时,您需要一个分布式锁管理器。我为此目的写了elock。有bigger ones和其他人选择忽略每个建议,并使用memcached完成相同的操作。
请不要将memcached用于轻量级咨询锁定。它旨在忘记一些东西。
我喜欢假装在制作网络应用时不存在文件系统。使规模更好。
答案 3 :(得分:5)
您可以使用简单文件锁定作为互斥机制,请参阅我的食谱here。它不适合所有场景,但是你没有说明为什么要使用这种类型的锁定。
答案 4 :(得分:3)
我最终得到了一个我自己涉及文件锁定的解决方案。如果这里的任何人最终使用它,请记住咨询锁和NFS不能很好地混合,所以请保持本地化。此外,这是一个阻塞锁,如果你想乱搞循环并不断检查,那么代码中有说明。
import os
import fcntl
class DjangoLock:
def __init__(self, filename):
self.filename = filename
# This will create it if it does not exist already
self.handle = open(filename, 'w')
# flock() is a blocking call unless it is bitwise ORed with LOCK_NB to avoid blocking
# on lock acquisition. This blocking is what I use to provide atomicity across forked
# Django processes since native python locks and semaphores only work at the thread level
def acquire(self):
fcntl.flock(self.handle, fcntl.LOCK_EX)
def release(self):
fcntl.flock(self.handle, fcntl.LOCK_UN)
def __del__(self):
self.handle.close()
Usage:
lock = DJangoLock('/tmp/djangolock.tmp')
lock.acquire()
try:
pass
finally:
lock.release()
答案 5 :(得分:2)
我没有写这篇文章,但我发现面对同样的问题非常有帮助:
http://chris-lamb.co.uk/2010/06/07/distributing-locking-python-and-redis/
基本上,您使用Redis服务器创建一个公开锁定功能的中央服务器。