本文介绍了Rails 中非线程安全的示例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我见过类似this 关于 Rails 中的线程安全以及有关该主题的各种网页,我相信每个人都擅长讲述它是什么,并就哪些不是线程安全的(类变量!")给出提示",但是我似乎永远找不到一个清晰、简单、完整的例子来说明在 Rails 中实际上不是线程安全的,以至于我想知道是否有人真正理解它.

I've seen threads like this on thread-safety in Rails and various web pages on the topic, and I'm sure everyone's great at reciting what it is and giving 'tips' on what isn't thread-safe ("class variables!"), but I can never seem to find a clear, simple, complete example of something that is actually not thread-safe in Rails, to the point where I wonder if anyone actually understands it at all.

如果有人能证明我是错的并给予,我会很感激:

I would be grateful if someone could prove me wrong and give:

  • 一个清晰、简单、完整的例子,说明了 Rails 中非线程安全的东西.代码在哪里应该很清楚(即,如果它在控制器中,请显示它),并且不应该让读者想象(例如不存在的方法).此外,不应有任何多余的代码或逻辑.

  • a clear, simple, complete example of something that is not thread-safe in Rails. It should be clear where the code is (i.e., if it is in the controller, please show it as such) and nothing should be left to the reader's imagination (such as a method that doesn't exist). Also, there shouldn't be any superfluous code or logic.

在两个用户同时在两个不同的线程上连接到网站的情况下,究竟会出现什么问题.

exactly how it would be problematic in the context of two users connecting to the website at the same time, on two different threads.

如何解决问题.

示例越重要且与 Rails 相关越好,因此,如果您能举出一个示例,说明一个用户可能会看到另一个用户的数据(或类似数据),请这样做.

The more significant and Rails-relevant the example, the better, so if you can give an example where one user might see another user's data (or similar), please do so.

推荐答案

注意
这只是部分答案,因为它是一个过时的读取示例(可能由多进程和多线程引起),OP 只是在寻找多线程问题.

假设您有一家商店向用户出售商品并相应地更新他的余额.

Here goes, imagine you have a store that sells an item to a user and updates his balance accordingly.

 PaymentsController

    if current_user.balance > item.price
       current_user.balance = current_user.balance - item.price #1
       current_user.create_purchase(item)  #2
       current_user.save #3
    end

这里的潜在问题是在条件内部(假设在第 1 行或第 2 行中)线程可以切换到不同的线程,完全运行,当我们返回原始线程时,余额现在是不同的值(仍然停留在第 1 行)它不知道这已经发生了!它可能允许余额不足的用户进行购买,并且还会用错误的值覆盖实际余额.

The potential problem here is that inside the condition (lets say in lines #1 or #2) the thread can switch to a different thread, run fully, the balance is now a different value yet when we return to the original thread (still stuck in line #1) it has no idea this has happened! It may allow a purchase for a user with not enough balance and it also override the real balance with a wrong value.

这是一个更具体的例子,说明这是如何发生的

Here's a more concrete example of how this can happen

让我们假设用户试图通过购买超过其余额允许的数量来玩我们的系统.项目 1 花费 100,项目 2 花费 75,他的余额为 100.

Let's imagine the user is trying to game our system by buying more than his balance allows him. Item 1 costs 100, Item 2 costs 75 and his balance is 100.

用户编写一个脚本来触发 2 个购买这些物品的帖子请求,以便他们几乎同时到达应用服务器.第一个请求命中第 1 行,就在第 2 行之前,线程切换到请求 2.第二个请求完全没有中断地运行 - 它购买第二个项目,因此新的实际余额现在是 25 (100 - 75).现在上下文切换到请求 1.请求 1 没有意识到实际余额是 25(它仍然认为用户有足够的余额来购买物品:记住请求 1 在第 2 行,在条件内切换!请求 1完成购买,然后将余额更新为 0 (100 - 100).用户刚刚购买的两件商品的价格超出了其余额应有的水平!

The user writes a script to fire 2 posts requests to purchase these items so they get almost simultaneously to the app server.The first requests hits line #1, and right before line #2 the thread switches to request 2.The second request runs fully with no interruption - it buys the second item so the new real balance is now 25 (100 - 75). Now the context switch to request 1. Request 1 does not realize that the real balance is 25 (it still thinks that the user had enough balance to buy the item: remember that request 1 switched at line #2, inside the condition! Request 1 completes the purchase and then updates the balance to be 0 (100 - 100). The user just bought two products that cost more than his balance should allow!

处理这种情况的一种方法是锁定 http://api.rubyonrails.org/classes/ActiveRecord/Locking/Pessimistic.html

A way to handle this situation is locking http://api.rubyonrails.org/classes/ActiveRecord/Locking/Pessimistic.html

这篇关于Rails 中非线程安全的示例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-22 14:30