Art*_*kel 26 ruby multithreading ruby-on-rails multiprocessing ruby-on-rails-4
我把一个简单的例子放在一起,尝试使用一个基本的例子来证明Rails中的并发请求.请注意,我使用的是MRI Ruby2和Rails 4.2.
def api_call
sleep(10)
render :json => "done"
end
Run Code Online (Sandbox Code Playgroud)
然后我在我的Mac(I7/4 Core)上的Chrome中找到4个不同的选项卡,看看它们是以串行还是并行方式运行(真正并发的是关闭但不是同一个东西).即,http:// localhost:3000/api_call
我不能使用Puma,Thin或Unicorn来使用它.每个请求都是串联的.10秒之后的第一个标签,20之后的第二个标签(因为它必须等待第一个完成),之后是第三个....
从我所读到的,我相信以下是真实的(请纠正我)并且是我的结果:
- unicorn.rb
worker_processes 4
preload_app true
timeout 30
listen 3000
after_fork do |server, worker|
ActiveRecord::Base.establish_connection
end
Run Code Online (Sandbox Code Playgroud)
所以,
有一个非常类似的问题,但是我无法解决这个问题并且它没有回答我关于使用MRI Ruby的并发请求的所有问题.
Github项目:https://github.com/afrankel/limitedBandwidth(注意:项目正在考虑的不仅仅是服务器上的多进程/线程问题)
Ely*_*Ely 24
我邀请你阅读Jesse Storimer的系列文章没有人理解GIL 这可能有助于你更好地理解一些MRI内部结构.
我也发现了Ruby的Pragmatic Concurrency,它看起来很有意思.它有一些同时测试的例子.
编辑: 此外我可以推荐文章删除config.threadsafe! 可能与Rails 4无关,但它解释了配置选项,其中一个可用于允许并发.
让我们讨论你的问题的答案.
即使使用Puma,您也可以使用多个线程(使用MRI).GIL确保一次只有一个线程是活动的,这是开发人员称为限制性的约束(因为没有真正的并行执行).请记住,GIL不保证线程安全.这并不意味着其他线程没有运行,他们正在等待轮到他们.它们可以交错(文章可以帮助更好地理解).
让我澄清一些术语:工人流程,线程.进程在单独的内存空间中运行,可以提供多个线程.同一进程的线程在共享内存空间中运行,这是其进程的空间.对于线程,我们指的是此上下文中的Ruby线程,而不是CPU线程.
关于你的问题的配置和你共享的GitHub repo,我认为一个合适的配置(我使用的是Puma)是设置4个worker和1到40个线程.这个想法是一个工人服务一个标签.每个标签最多可发送10个请求.
让我们开始吧:
我在虚拟机上使用Ubuntu.首先,我在我的虚拟机设置中启用了4个核心(以及其他一些我认为可能有用的设置).我可以在我的机器上验证这一点.所以我接受了.
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
Run Code Online (Sandbox Code Playgroud)
我使用了你的共享GitHub项目并稍微修改了它.我创建了一个名为puma.rb
(放在config
目录中)的Puma配置文件,其中包含以下内容:
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
Run Code Online (Sandbox Code Playgroud)
默认情况下,Puma以1个worker和1个线程启动.您可以使用环境变量来修改这些参数.我这样做了:
export MAX_THREADS=40
export WEB_CONCURRENCY=4
Run Code Online (Sandbox Code Playgroud)
要使用此配置启动Puma,我输入了
bundle exec puma -C config/puma.rb
Run Code Online (Sandbox Code Playgroud)
在Rails应用程序目录中.
我用四个标签打开浏览器来调用应用程序的URL.
第一个请求是在15:45:05左右开始的,最后一个请求是在15:49:44左右.这是4分39秒的经过时间.您还可以在日志文件中以非排序顺序查看请求的ID.(见下文)
GitHub项目中的每个API调用都会休眠15秒.我们有4个4个选项卡,每个选项卡有10个API调用.这使得最大经过时间为600秒,即10分钟(在严格的串行模式下).
理论上的理想结果将是并行的,并且经过的时间不会超过15秒,但我根本没想到.我不确定结果究竟是什么,但我仍然感到非常惊讶(考虑到我在虚拟机上运行并且MRI受到GIL和其他一些因素的限制).该测试的经过时间小于最大经过时间的一半(在严格的串行模式下),我们将结果减少到不到一半.
编辑我进一步阅读了围绕每个请求包含互斥锁的Rack :: Lock(上面的第三篇文章).我找到了
config.allow_concurrency = true
节省时间的选择 .有一点需要注意的是增加连接池(尽管请求不进行查询,因此必须相应地设置数据库); 最大线程数是一个很好的默认值.在这种情况下为40.我用jRuby测试了应用程序,实际经过的时间是2分钟,其中allow_concurrency = true.
我用MRI测试了应用程序,实际经过的时间是1分47秒,其中allow_concurrency = true.这对我来说是个大惊喜.这真让我感到惊讶,因为我预计MRI会慢于JRuby.它不是.这使我质疑关于MRI和JRuby之间速度差异的广泛讨论.
现在,观察不同选项卡上的响应"更随机".在选项卡1之前完成选项卡3或4,我首先请求.
我认为因为你没有竞争条件,所以测试似乎没问题.但是,如果在实际应用程序中设置config.allow_concurrency = true,我不确定应用程序的广泛后果.
请随时查看,并让我知道您的读者可能有的任何反馈.我的机器上还有克隆.如果您有兴趣,请告诉我.
按顺序回答您的问题:
日志文件Rails应用程序:
**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
Run Code Online (Sandbox Code Playgroud)
**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
Run Code Online (Sandbox Code Playgroud)
**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
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
3743 次 |
最近记录: |