首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用MRI Ruby并发请求

使用MRI Ruby并发请求
EN

Stack Overflow用户
提问于 2015-04-29 21:55:17
回答 2查看 4.6K关注 0票数 26

我举了一个简单的例子,试图用一个基本的例子来证明Rails中的并发请求。注意,我使用的是MRI、Ruby2和Rails 4.2。

代码语言:javascript
复制
  def api_call
    sleep(10)
    render :json => "done"
  end

然后,我在我的mac (I7 /4 Core)上查看Chrome中的4个不同的选项卡,看看它们是串联运行还是并行运行(确实是并行的,这是非常接近的,但不是一回事)。即,打电话

我不能用美洲豹,瘦或独角兽来完成这个任务。每一个请求都是依次提出的。第一个标签在10秒后,第二个选项卡在20秒后(因为它必须等待第一个选项卡完成),第三个选项卡在那之后.

根据我所读到的,我相信以下是正确的(请纠正我),并且是我的结果:

  • 独角兽是多进程的,我的例子应该是有效的(在定义了unicorn.rb配置文件中的工人数量之后),但是没有。我可以看到4个工作人员在开始工作,但一切都是串联的。我使用的是独角兽- rails创业板,使用独角兽-c配置/ unicorn.rb启动rails,在我的unicorn.rb中有:

-- unicorn.rb

代码语言:javascript
复制
worker_processes 4
preload_app true
timeout 30
listen 3000
after_fork do |server, worker|
  ActiveRecord::Base.establish_connection
end
  • Thin和Puma是多线程的(尽管美洲狮至少有一个“聚类”模式,您可以使用-w参数启动工作人员),并且不应该使用MRIRuby2.0(在多线程模式下),因为“存在一个确保一次只能运行一个线程的全局解释器锁(GIL)”。

所以,

  • 我是否有一个有效的例子(或者使用睡眠是错误的)?
  • 我上面关于多进程和多线程的陈述(关于MRI 2)正确吗?
  • 对于为什么我不能让它与Unicorn (或任何服务器)一起工作,有什么想法吗?

有一个非常类似于我的问题,但我无法使它的工作,因为我的回答,它没有回答我所有的问题,并发请求使用MRI。

Github项目:https://github.com/afrankel/limitedBandwidth (注意:项目正在研究的不仅仅是服务器上的多进程/线程问题)

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-05-07 09:56:19

我邀请你阅读杰西斯托默尔的没有人理解吉尔系列,它可能会帮助你更好地理解一些核磁共振内部。

我还发现了与Ruby的语用并发,它读起来很有趣。它有一些并发测试的例子。

编辑:另外,我可以推荐文章移除config.threadsafe!可能与Rails 4无关,但它解释了配置选项,您可以使用其中一个选项来允许并发。

让我们讨论一下你问题的答案。

您可以有几个线程(使用MRI),即使是美洲豹。GIL确保一次只有一个线程是活动的,这是开发人员称之为限制的约束(因为没有真正的并行执行)。请记住,GIL并不保证线程安全。这并不意味着其他线程没有运行,而是在等待轮到它们。它们可以相互交织(文章有助于更好地理解)。

让我澄清一些术语:工作进程,线程。一个进程在一个单独的内存空间中运行,可以为多个线程服务。同一进程的线程在共享内存空间中运行,这是它们的进程的线程。对于线程,我们指的是这个上下文中的Ruby线程,而不是CPU线程。

关于您的问题的配置和您共享的GitHub回购,我认为一个合适的配置(我使用了Puma)是设置4个工作人员和1到40个线程。这个想法是,一个工人提供一个标签。每个选项卡最多发送10个请求。

让我们开始吧:

我在Ubuntu虚拟机上工作。因此,首先,我在虚拟机的设置中启用了4个内核(以及一些我认为可能有用的其他设置)。我可以在我的机器上验证这个。所以我就同意了。

代码语言:javascript
复制
Linux command --> lscpu
Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                4
On-line CPU(s) list:   0-3
Thread(s) per core:    1
Core(s) per socket:    4
Socket(s):             1
NUMA node(s):          1
Vendor ID:             GenuineIntel
CPU family:            6
Model:                 69
Stepping:              1
CPU MHz:               2306.141
BogoMIPS:              4612.28
L1d cache:             32K
L1d cache:             32K
L2d cache:             6144K
NUMA node0 CPU(s):     0-3

我使用了您的共享GitHub项目,并稍微修改了它。我创建了一个名为puma.rb的彪马配置文件(放在config目录中),其内容如下:

代码语言:javascript
复制
workers Integer(ENV['WEB_CONCURRENCY'] || 1)
threads_count = Integer(ENV['MAX_THREADS'] || 1)
threads 1, threads_count

preload_app!

rackup      DefaultRackup
port        ENV['PORT']     || 3000
environment ENV['RACK_ENV'] || 'development'

on_worker_boot do
  # Worker specific setup for Rails 4.1+
  # See: https://devcenter.heroku.com/articles/deploying-rails-applications-with-the-puma-web-server#on-worker-boot
  #ActiveRecord::Base.establish_connection
end

默认情况下,Puma由1个worker和1个线程启动。您可以使用环境变量来修改这些参数。我这样做了:

代码语言:javascript
复制
export MAX_THREADS=40
export WEB_CONCURRENCY=4

要用我输入的配置启动Puma

代码语言:javascript
复制
bundle exec puma -C config/puma.rb

在Rails应用程序目录中。

我打开带有四个选项卡的浏览器来调用应用程序的URL。

第一次请求开始于15:45:05,最后一次请求是在15h49:44左右。这是经过4分39秒的时间。此外,您还可以在日志文件中看到请求的id的非排序顺序。(见下文)

GitHub项目中的每个API调用都休眠15秒。我们有4个选项卡,每个选项卡都有10个API调用。这使得最长运行时间为600秒,即10分钟(在严格的串行模式下)。

理论上理想的结果将是并行的,时间不会超过15秒,但我一点也没想到。我不知道结果究竟是什么,但我仍然非常惊讶(考虑到我在虚拟机上运行,核磁共振受GIL和其他一些因素的限制)。这个测试的运行时间少于最大运行时间的一半(在严格的串行模式下),我们将结果减少到不足一半。

编辑--我进一步阅读了关于Rack::Lock的文章,它在每个请求周围包装了一个互斥体(上面的第三篇文章)。我发现config.allow_concurrency = true选项可以节省时间。一个小小的警告是增加连接池(尽管请求没有查询,数据库必须相应地设置);最大线程数是一个很好的缺省值。40在这个案子里。 我用jRuby测试了这个应用程序,实际使用allow_concurrency=true的时间是2分钟。 我用核磁共振对应用程序进行了测试,用allow_concurrency=true测试了实际运行时间为1分钟47秒。这对我来说是个大惊喜。这真的让我感到惊讶,因为我预计核磁共振要比JRuby慢。事实并非如此。这让我质疑关于磁共振成像和JRuby速度差异的广泛讨论。 现在看不同标签上的回复是“更随意的”了。发生在选项卡1之前完成选项卡3或4,这是我首先请求的。 我想因为你没有比赛条件,所以考试似乎没问题。但是,如果在实际应用程序中设置config.allow_concurrency=true,我不确定应用程序范围的后果。

请随时查看,并让我知道您的读者可能有任何反馈。我的机器上还有克隆人。如果你有兴趣,请告诉我。

按顺序回答你的问题:

  • 我认为你的例子在结果上是正确的。但是,对于并发性,最好使用共享资源进行测试(例如,在第二篇文章中)。
  • 关于您的声明,正如在这个答案的开头提到的,MRI是多线程的,但是受到GIL的限制,一次只能有一个活动线程。这就引出了一个问题:使用MRI,用更多的进程和更少的线程进行测试不是更好吗?我真的不知道,一个初步的猜测将是相当没有或没有太大的区别。也许有人能弄清楚这件事。
  • 我觉得你的例子很好。只是需要稍微修改一下。

附录

日志文件Rails应用程序:

代码语言:javascript
复制
**config.allow_concurrency = false (by default)**
-> Ideally 1 worker per core, each worker servers up to 10 threads.

[3045] Puma starting in cluster mode...
[3045] * Version 2.11.2 (ruby 2.1.5-p273), codename: Intrepid Squirrel
[3045] * Min threads: 1, max threads: 40
[3045] * Environment: development
[3045] * Process workers: 4
[3045] * Preloading application
[3045] * Listening on tcp://0.0.0.0:3000
[3045] Use Ctrl-C to stop
[3045] - Worker 0 (pid: 3075) booted, phase: 0
[3045] - Worker 1 (pid: 3080) booted, phase: 0
[3045] - Worker 2 (pid: 3087) booted, phase: 0
[3045] - Worker 3 (pid: 3098) booted, phase: 0
Started GET "/assets/angular-ui-router/release/angular-ui-router.js?body=1" for 127.0.0.1 at 2015-05-11 15:45:05 +0800
...
...
...
Processing by ApplicationController#api_call as JSON
  Parameters: {"t"=>"15?id=9"}
Completed 200 OK in 15002ms (Views: 0.2ms | ActiveRecord: 0.0ms)
[3075] 127.0.0.1 - - [11/May/2015:15:49:44 +0800] "GET /api_call.json?t=15?id=9 HTTP/1.1" 304 - 60.0230
代码语言:javascript
复制
**config.allow_concurrency = true**
-> Ideally 1 worker per core, each worker servers up to 10 threads.

[22802] Puma starting in cluster mode...
[22802] * Version 2.11.2 (ruby 2.2.0-p0), codename: Intrepid Squirrel
[22802] * Min threads: 1, max threads: 40
[22802] * Environment: development
[22802] * Process workers: 4
[22802] * Preloading application
[22802] * Listening on tcp://0.0.0.0:3000
[22802] Use Ctrl-C to stop
[22802] - Worker 0 (pid: 22832) booted, phase: 0
[22802] - Worker 1 (pid: 22835) booted, phase: 0
[22802] - Worker 3 (pid: 22852) booted, phase: 0
[22802] - Worker 2 (pid: 22843) booted, phase: 0
Started GET "/" for 127.0.0.1 at 2015-05-13 17:58:20 +0800
Processing by ApplicationController#index as HTML
  Rendered application/index.html.erb within layouts/application (3.6ms)
Completed 200 OK in 216ms (Views: 200.0ms | ActiveRecord: 0.0ms)
[22832] 127.0.0.1 - - [13/May/2015:17:58:20 +0800] "GET / HTTP/1.1" 200 - 0.8190
...
...
...
Completed 200 OK in 15003ms (Views: 0.1ms | ActiveRecord: 0.0ms)
[22852] 127.0.0.1 - - [13/May/2015:18:00:07 +0800] "GET /api_call.json?t=15?id=10 HTTP/1.1" 304 - 15.0103
代码语言:javascript
复制
**config.allow_concurrency = true (by default)**
-> Ideally each thread serves a request.

Puma starting in single mode...
* Version 2.11.2 (jruby 2.2.2), codename: Intrepid Squirrel
* Min threads: 1, max threads: 40
* Environment: development
NOTE: ActiveRecord 4.2 is not (yet) fully supported by AR-JDBC, please help us finish 4.2 support - check http://bit.ly/jruby-42 for starters
* Listening on tcp://0.0.0.0:3000
Use Ctrl-C to stop
Started GET "/" for 127.0.0.1 at 2015-05-13 18:23:04 +0800
Processing by ApplicationController#index as HTML
  Rendered application/index.html.erb within layouts/application (35.0ms)
...
...
...
Completed 200 OK in 15020ms (Views: 0.7ms | ActiveRecord: 0.0ms)
127.0.0.1 - - [13/May/2015:18:25:19 +0800] "GET /api_call.json?t=15?id=9 HTTP/1.1" 304 - 15.0640
票数 25
EN

Stack Overflow用户

发布于 2015-12-26 10:45:24

对于“Elyasin”和“Arthur Frankel”,我创建了这个存储库,用于测试在MRI和JRuby中运行的美洲豹。在这个小项目中,我没有做sleep来模拟一个长时间运行的请求。正如我在MRI中发现的那样,GIL似乎与常规处理不同,更类似于外部I/O请求。

我把斐波纳契序列计算放在控制器里。在我的机器上,fib(39)在JRuby中花费了6.x秒,在MRI上花费了11秒,这足以显示出两者之间的差异。

我打开了两个浏览器窗口。我这样做不是在同一个浏览器中打开选项卡,而是为了防止浏览器发送到同一个域的并发请求受到某些限制。我现在确定了细节,但是两种不同的浏览器足以防止这种情况发生。

我测试了薄层+核磁共振,然后是美洲狮+核磁共振,然后是美洲狮+ JRuby。研究结果如下:

  1. thin + MRI:不奇怪,当我快速重新加载两个浏览器时,第一个浏览器在11秒后完成。然后第二个请求开始了,又用了11秒才完成。
  2. 让我们先谈谈美洲豹+ JRuby。当我快速重新加载这两个浏览器时,它们似乎几乎在同一秒钟内启动,并且在同一秒钟内也完成了。两人都花了大约6.9秒才完成。Puma是一个多线程服务器,JRuby支持多线程.
  3. 最后是美洲豹+核磁共振。在我快速重新加载这两个浏览器之后,这两个浏览器都花了22秒钟才完成。他们几乎在同一秒钟开始,几乎在同一秒钟完成。但两人都花了两次时间才完成。这正是GIL所做的:在线程之间切换以获得并发性,但是锁本身阻止并行性的发生。

关于我的设置:

  • 服务器都是在Rails生产模式下启动的。在生产模式中,config.cache_classes被设置为true,这意味着config.allow_concurrency = true
  • Puma以8个线程min和8个最大线程启动。
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29955290

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档