【问题标题】:Example of something that is not thread-safe in RailsRails 中非线程安全的示例
【发布时间】:2016-11-29 23:13:49
【问题描述】:

我在 Rails 中的线程安全和各种网页上看到过类似 this 的线程以及有关该主题的各种网页,我相信每个人都擅长背诵它是什么并就什么不是线程给出“提示”-安全的(“类变量!”),但我似乎永远无法找到一个清晰、简单、完整的示例,说明实际上不是线程安全的 Rails,以至于我想知道是否有人其实完全懂。

如果有人能证明我错了,我将不胜感激:

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

  • 在两个用户同时在两个不同线程上连接到网站的情况下,这将是怎样的问题。

  • 如何解决问题。

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

【问题讨论】:

  • 您可能想阅读Removing config.threadsafe! blog post,它会清除一切。
  • 我不同意我的帖子的编辑。类变量不是一个合适的标签,帖子标题现在是一个陈述而不是一个问题。

标签: ruby-on-rails thread-safety class-variables


【解决方案1】:

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

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

 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 行)它不知道这已经发生了!它可能允许余额不足的用户进行购买,并且还会以错误的值覆盖实际余额。

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

让我们想象一下,用户试图通过购买超出其余额允许的数量来玩弄我们的系统。第 1 项花费 100,第 2 项花费 75,他的余额为 100。

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

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

【讨论】:

  • 我相信这类事情发生的次数比我们想象的要多,但如果它不是我们应用程序的关键部分(例如我们更新页面的查看次数),我们就不会注意到。
  • OP 要求提供一个线程安全问题的示例。这是一个通用的请求并发问题。 (而且,是的,在数据​​库级别锁定记录是解决它的方法。)
  • 没错,我展示的是一个过时的数据问题,这可能是由多线程或多进程引起的。我将留下这个答案,因为我相信它有一些价值。 OP似乎正在寻找共享类变量问题,也许其他人可以提出一个例子
  • @Joel_Blum 很想进一步了解这一点,在您的示例中,您将如何重写代码以避免潜在问题?
猜你喜欢
  • 1970-01-01
  • 2019-05-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-31
  • 2011-03-30
  • 2010-12-10
相关资源
最近更新 更多