了解多个枪支过程的工作

发布于 2025-01-20 22:44:11 字数 642 浏览 2 评论 0原文

我不知道我想要理解的是什么,上网把我带到了这里,现在我的代码中需要这个。

我使用 django-rest-framework、gunicorn 和 Nginx。

假设我有 3 个gunicorn 设置的工作进程。

我有一个非常简单的视图,它从数据库读取一个值,执行一项不同的任务,大约需要 1 秒,将值增加 1,然后将其保存回数据库。

class CreateView():
    value = MyModel.objects.get(id=1).integerValueField
    otherTask() #takes around 1 second (assume)
    updatedValue = value + 1
    MyModel.objects.filter(id=1).update(integerValueField=updatedValue)
    return

这总是有效吗?

如果gunicorn的不同工作进程正在处理并发用户的请求怎么办?如果数据库(integerValueField 字段)由不同的进程读取值和由其他工作进程更新值之间进行更新?是否以某种方式锁定以保持完整性?

如果我可以获得有效的链接来阅读有关该主题的更多信息,对我来说会很有效。

I have no knowledge of what I'm trying to understand, surfing the internet brought me here and now I need this in my code.

I use django-rest-framework, gunicorn, and Nginx.

Suppose I have 3 workers process of gunicorn setup.

and I have a very simple view that reads a value from the database, performs a different task that takes around 1 second, increments the value by 1, and saves it back to the database.

class CreateView():
    value = MyModel.objects.get(id=1).integerValueField
    otherTask() #takes around 1 second (assume)
    updatedValue = value + 1
    MyModel.objects.filter(id=1).update(integerValueField=updatedValue)
    return

Will this always work?

what if a different worker process of gunicorn is handling the request of concurrent users? If the database is updated (integerValueField field) by a different process in between reading the value and updating the value by some other worker process? Is this locked somehow to maintain integrity?

if I can get valid links to read more about the topic, will work well for me.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

孤星 2025-01-27 22:44:11

扩展 Pjot 的评论 - 不,如果您使用多个 Gunicorn 工作人员执行您提供的代码,则该代码将无法可靠地工作。这里发生的事情被称为竞争条件,实际上并不是 Django 特有的任何东西 - < a href="https://stackoverflow.com/questions/9850336/database-race-conditions">这里是在更通用的数据库设置中对此进行的讨论。

现在,如果多个 Gunicorn 工作人员访问同一个对象(或者如果我们假设 MyModel.objects.get(id=1).integerValueField 开头为 100,则具有多个线程的单个工作线程)看起来大致如下:

  1. worker 1 执行value = MyModel.objects.get(id=1).integerValueField,这将访问数据库并使用主键 1 检索对象并将其存储在内存中。 value 将设置为 integerValueField 的值,在我们的示例中,
  2. worker 1 执行 otherTask()
  3. 100 Worker 2 执行 value = MyModel.objects.get(id=1).integerValueField 并且与 Worker 1 一样,它将把 integerValueField 的当前值存储在数据库中。 时该值尚未更改,
  4. value 再次为 100,因为数据库工作线程 2 执行 otherTask()
  5. 工作线程 1 现在将执行updatedValue = value + 1,将updatedValue设置为101,然后执行MyModel.objects.filter(id=1).update(integerValueField=updatedValue) 将其保存到数据库
  6. 工作线程 2 现在也将执行 updatedValue = value + 1 -但 value 也将是 101 而不是 102,因为使用了数据库值的本地副本。这里不会发生额外的数据库访问。之后它也会执行 MyModel.objects.filter(id=1).update(integerValueField=updatedValue) ,这将更新数据库,但不会更改值 - 它仍然会101

select_for_update 的作用是锁定数据库行,以便任何其他工作线程无法同时访问该行(这是一个称为 互斥访问,通常通过 锁定)。这将解决您丢失更新的问题。但是,您在这里应该考虑的是,当 otherTask() 正在运行时(这显然是很长的时间),您将阻止对此行的所有访问,这很容易导致您的客户端长时间延迟更糟糕的是。
我真的会考虑是否有更好的方法来解决这个问题。如果不是,我至少会研究 多-线程 Gunicorn 工人 - 这里是一个很好的讨论。

To expand on The Pjot‘s comment - no, the code you provided won't work reliably if you execute it with multiple Gunicorn workers. What happens here is called a race condition and isn't actually anything that is specific to Django - here is a discussion of exactly this in a more general database setting.

Now, what would happen in your specific case if multiple Gunicorn workers access the same object (or a single worker with multiple threads) looks roughly like this if we assume that MyModel.objects.get(id=1).integerValueField is 100 at the beginning:

  1. worker 1 executes value = MyModel.objects.get(id=1).integerValueField, which will hit the database and retrieve the object with primary key 1 and store it in memory. value will be set to the value of integerValueField, which is 100in our example
  2. worker 1 executes otherTask()
  3. worker 2 executes value = MyModel.objects.get(id=1).integerValueField and just as worker 1 it will store the current value of integerValueField in the database in value. value, again, will be 100 as the value hasn't yet changed in the database
  4. worker 2 executes otherTask()
  5. worker 1 will now execute updatedValue = value + 1, which sets updatedValue to 101 and then execute MyModel.objects.filter(id=1).update(integerValueField=updatedValue) to save it to the database
  6. worker 2 will now execute updatedValue = value + 1 as well - but value will be also 101 instead of 102, as the local copy of the database value is used. No additional database access happens here. After that it will execute MyModel.objects.filter(id=1).update(integerValueField=updatedValue) as well, which will update the database, but won't change the value - it still will be 101

What select_for_update does is it locks the database row so it cannot be accessed by any other worker at the same time (this is a concept that is called mutual exclusive access and is often implemented through locking). This will solve your issue of lost updates. However, what you should consider here is that you will block all access to this row while the otherTask() is running (which is apparently a substantial time) and this can easily lead to long delays for your clients and worse.
I'd really consider if there isn't a better way to solve this. If not I'd at least look into multi-threaded Gunicorn workers - here is a good discussion.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文