Python Django的种族状况
在Django,我遇到了一些严重的比赛情况。当两个运行程序试图同时执行某个_method()时,问题就开始了。创建的日志记录如下所示:Python Django的种族状况,python,django,race-condition,Python,Django,Race Condition,在Django,我遇到了一些严重的比赛情况。当两个运行程序试图同时执行某个_method()时,问题就开始了。创建的日志记录如下所示: Job 3: Candidate Job 3: Already taken Job 3: Candidate Job 3: Already taken Job 3: Candidate Job 3: Already taken (et cetera for 18 MB) 下面的方法给我带来了麻烦。应该注意的是,该方法将重新运行,直到该方法返回False: de
Job 3: Candidate
Job 3: Already taken
Job 3: Candidate
Job 3: Already taken
Job 3: Candidate
Job 3: Already taken
(et cetera for 18 MB)
下面的方法给我带来了麻烦。应该注意的是,该方法将重新运行,直到该方法返回False
:
def some_method():
conditions = #(amongst others, excludes jobs with status EXECUTING)
try:
cjob = Job.objects.filter(conditions).order_by(some_fields)[0]
except IndexError:
return False
print 'Job %s: Candidate' % cjob.id
job = cjob.for_update()
if cjob.status != job.status:
print 'Job %s: Already taken' % cjob.id
return True
print 'Job %s: Starting...' % job.id
job.status = Job.EXECUTING
job.save()
# Critical section
# In models.py:
class Job(models.Model):
# ...
def for_update(self):
return Job.objects.raw('SELECT * FROM `backend_job` WHERE `id` = %s FOR UPDATE', (self.id, ))[0]
目前,Django没有一个专用的for_update-method,为了防止创建带有我们用来确定是否必须运行作业的所有条件的查询,我们在简单for update查询之前先执行困难的查询
我真的不明白这怎么会造成我们所看到的麻烦,我们执行查询,然后执行语句,当另一个运行人员持有作业的锁时,该语句将被阻止。只有在作业状态更改后,才会释放锁。第二个运行程序现在获得锁,但作业的状态已更改,因此它从方法返回,只是稍后重新输入;但是cjob
-查询不会再次返回相同的作业,因为其状态现在已被过滤器排除
我是误解了FOR UPDATE子句,还是遗漏了其他内容
需要注意的是,我在InnoDB中使用MySQL,芹菜不适合此解决方案。手动更新事务解决了此问题。自事务开始以来,QuerySet似乎没有更新。当两个查询集以某种方式同时启动时,两个查询集中都会出现一个作业,这会使跑步者分道扬镳
阅读之后,我想出了一个解决方案:在
返回True
之前,事务已提交。job.status和cjob.status
的值是什么?类型是什么?这些是单个字符:Job.EXECUTING=='E'。第5行的查询不包括状态为“E”的作业(实际上,它只接受状态为“W”或“N”的作业)。