34

我正在尝试在 Rails 4 中同时处理多个请求,我可以在 Rails 3 中非常轻松地做到这config.threadsafe!一点Puma

说我有这个控制器

class ConcurrentController < ApplicationController
  def index
    sleep 10000
  end

  def show
  end
end

我曾经能够用puma -t 2:16 -p 3000(最少 2 个线程)启动 puma,然后点击index,然后show仍然可以show正确渲染。

在 Rails 4 中,如果我尝试做同样的事情,Puma 现在会锁定index请求并且show永远不会被渲染。当我点击Ctrl-C服务器时,Puma 给了我这个错误:

Rack app error: #<ThreadError: Attempt to unlock a mutex which is locked by another thread>

为了让并发与 Rails 4 一起工作,我在这里缺少什么?config.threadsafe!应该不需要(即使我尝试也没有什么不同)

4

3 回答 3

38

我邀请您阅读config.threadsafe!本文删除 config.threadsafe 中的配置选项! 它将帮助您更好地理解 的选项config.threadsafe!,特别是允许并发。

在 Rails 4config.threadsafe!中默认设置。


现在来回答

在 Rails 4 中,请求默认由 DEV 环境中的 Rack::Lock 中间件包裹在 Mutex 周围。

如果要启用并发,可以设置config.allow_concurrency=true. 这将禁用 Rack::Lock 中间件。如您的问题的另一个答案中所述,我不会删除它;这对我来说就像一个黑客。

注意:如果您config.cache_classes=true对 (Rack::Lock request mutex) 进行了分配,config.allow_concurrency则默认情况下允许并发请求。如果有 config.cache_classes=false,则可以设置 config.allow_concurrencytruefalse。在 DEV 环境中,你会想要这样

config.cache_classes=false
config.allow_concurrency=true

声明:这意味着如果 config.cache_classes = false (默认情况下在 dev env 中)我们不能有并发请求。是不正确的。

附录

您可以参考这个答案,它设置了一个使用 MRI 和 JRuby 测试并发性的实验。结果令人惊讶。MRI 比 JRuby 快。

MRI 并发实验在 GitHub 上。实验只测试并发请求。控制器中没有竞争条件。但是,我认为实现上面文章中的示例来测试控制器中的竞争条件并不难。

于 2015-05-14T02:02:58.693 回答
22

似乎默认情况下,在 Rails 4 中,开发环境中没有启用并发请求。

我在文档中找到了这句话。

Rack::Lock 将应用程序包装在互斥体中,因此一次只能由单个线程调用。仅在 config.cache_classes 为 false 时启用。

这意味着如果config.cache_classes = false(默认情况下在开发环境中)我们不能有并发请求。

并发请求确实适用于我在生产环境中的示例。

一种解决方案是config.cache_classes = true在开发环境中设置,但随后代码不会在更改时重新加载,这对于开发来说并不真正起作用。

第二种 hacky 解决方案是Rack::Lock在开发中禁用中间件。

因此,如果您要添加development.rb以下行:

config.middleware.delete Rack::Lock

您应该能够在禁用缓存类的开发环境中进行并发请求。

于 2014-05-12T11:33:43.263 回答
-1

你可以试试独角兽这在开发模式下非常简单:

http://dave.is/unicorn.html

于 2014-05-09T11:34:31.417 回答