mri ruby gil
Transcript of mri ruby gil
• Обработка запроса в многопоточном сервере (Puma) может быть очень долгим
• Как реализована многопоточность в MRI Ruby
• Как работает планировщик и приоритетность
• Что внутри EventMachine
• Когда вам могут понадобиться файберы
• Дальнейшее развитие многопоточности в Ruby
MRI
model 1: Userlevel Thread Same as traditional ruby thread.
model 2: Native Thread with Global VM lock Using pthread and Ruby threads run concurrent.
model 3: Native Thread with fine grain lock Using pthread and Ruby threads run concurrent or parallel.
YARV Thread Design
MRI
model 1: Userlevel Thread Same as traditional ruby thread.
model 2: Native Thread with Global VM lock Using pthread and Ruby threads run concurrent.
model 3: Native Thread with fine grain lock Using pthread and Ruby threads run concurrent or parallel.
YARV Thread Design
MRI
model 1: Userlevel Thread Same as traditional ruby thread.
model 2: Native Thread with Global VM lock Using pthread and Ruby threads run concurrent.
model 3: Native Thread with fine grain lock Using pthread and Ruby threads run concurrent or parallel.
YARV Thread Design
MRI
model 1: Userlevel Thread Same as traditional ruby thread.
model 2: Native Thread with Global VM lock Using pthread and Ruby threads run concurrent.
model 3: Native Thread with fine grain lock Using pthread and Ruby threads run concurrent or parallel.
YARV Thread Design
At Ruby Kaigi 2016, Koichi Sasada
$ (curl -i localhost:3000); (curl -i localhost:3000);
HTTP/1.1 200 OK X-Request-Id: 839cc258-019b-4737-b169-60b05caaceca X-Runtime: 0.139625
HTTP/1.1 200 OK X-Request-Id: a3d85a32-53e6-4a5a-99cd-190f6f48f964 X-Runtime: 0.130910
$ (curl -i localhost:3000 &); (curl -i localhost:3000 &);
HTTP/1.1 200 OK X-Request-Id: 14183c91-7e27-4f7f-be3d-d06814fa6c55 X-Runtime: 0.278702
HTTP/1.1 200 OK X-Request-Id: 0ff1ed87-3f54-4afd-af34-218601bbafea X-Runtime: 0.276639
(curl -i localhost:3000 &) x5
1) X-Runtime: 0.682356
2) X-Runtime: 0.682923
3) X-Runtime: 0.481979
4) X-Runtime: 0.412355
5) X-Runtime: 0.414157
while (system_working > 0) { /* timer function */
ubf_wakeup_all_threads(); timer_thread_function(0); if (TT_DEBUG) WRITE_CONST(2, "tick\n"); /* wait */
timer_thread_sleep(gvl); }
while (system_working > 0) { /* timer function */
ubf_wakeup_all_threads(); timer_thread_function(0); if (TT_DEBUG) WRITE_CONST(2, "tick\n"); /* wait */
timer_thread_sleep(gvl); }
while (system_working > 0) { /* timer function */
ubf_wakeup_all_threads(); timer_thread_function(0); if (TT_DEBUG) WRITE_CONST(2, "tick\n"); /* wait */
timer_thread_sleep(gvl); }
while (system_working > 0) { /* timer function */
ubf_wakeup_all_threads(); timer_thread_function(0); if (TT_DEBUG) WRITE_CONST(2, "tick\n"); /* wait */
timer_thread_sleep(gvl); }
/* 100ms. 10ms is too small for user level thread scheduling * on recent Linux (tested on 2.6.35) */
#define TIME_QUANTUM_USEC (100 * 1000)
if (th->priority > 0) limits_us <<= th->priority; Else
limits_us >>= -th->priority;
if (th->status == THREAD_RUNNABLE) th->running_time_us += TIME_QUANTUM_USEC; rb_thread_schedule_limits(limits_us)
rb_thread_schedule_limits(unsigned long limits_us) { if (th->running_time_us >= limits_us) { /* … */ } }
goliathGoliath is an open source version of the non-blocking (asynchronous)
Ruby web server framework.
EM.run do res = EventMachine::HttpRequest.new("https://www.ruby-lang.org/").aget res.callback { p res.response } end
_UpdateTime(); _RunTimers();
_AddNewDescriptors(); _ModifyDescriptors();
_RunEpollOnce();
_DispatchHeartbeats(); _CleanupSockets();
if (bTerminateSignalReceived) return false;
_UpdateTime();_RunTimers();
_AddNewDescriptors(); _ModifyDescriptors();
_RunEpollOnce();
_DispatchHeartbeats(); _CleanupSockets();
if (bTerminateSignalReceived) return false;
_UpdateTime(); _RunTimers();
_AddNewDescriptors();_ModifyDescriptors();
_RunEpollOnce();
_DispatchHeartbeats(); _CleanupSockets();
if (bTerminateSignalReceived) return false;
_UpdateTime(); _RunTimers();
_AddNewDescriptors(); _ModifyDescriptors();
_RunEpollOnce();
_DispatchHeartbeats(); _CleanupSockets();
if (bTerminateSignalReceived) return false;
EM.run do
fiber = Fiber.new do current_fiber = Fiber.current p 1 res = EventMachine::HttpRequest.new("https://www.ruby-lang.org/").aget res.callback { p 4; current_fiber.resume(5) } p 2 puts Fiber.yield p 6 end p 0 fiber.resume p 3 end
EM.run do
fiber = Fiber.new do current_fiber = Fiber.current p 1 res = EventMachine::HttpRequest.new("https://www.ruby-lang.org/").aget res.callback { p 4; current_fiber.resume(5) } p 2 puts Fiber.yield p 6 end p 0 fiber.resume p 3 end
EM.run do
fiber = Fiber.new do current_fiber = Fiber.current p 1 res = EventMachine::HttpRequest.new("https://www.ruby-lang.org/").aget res.callback { p 4; current_fiber.resume(5) } p 2 puts Fiber.yield p 6 end p 0 fiber.resume p 3 end
EM.run do
fiber = Fiber.new do current_fiber = Fiber.current p 1 res = EventMachine::HttpRequest.new("https://www.ruby-lang.org/").aget res.callback { p 4; current_fiber.resume(5) } p 2 puts Fiber.yield p 6 end p 0 fiber.resume p 3 end
EM.run do
fiber = Fiber.new do current_fiber = Fiber.current p 1 res = EventMachine::HttpRequest.new("https://www.ruby-lang.org/").aget res.callback { p 4; current_fiber.resume(5) } p 2 puts Fiber.yield p 6 end p 0 fiber.resume p 3 end
EM.run do
fiber = Fiber.new do current_fiber = Fiber.current p 1 res = EventMachine::HttpRequest.new("https://www.ruby-lang.org/").aget res.callback { p 4; current_fiber.resume(5) } p 2 puts Fiber.yield p 6 end p 0 fiber.resume p 3 end
EM.run do
fiber = Fiber.new do current_fiber = Fiber.current p 1 res = EventMachine::HttpRequest.new("https://www.ruby-lang.org/").aget res.callback { p 4; current_fiber.resume(5) } p 2 puts Fiber.yield p 6 end p 0 fiber.resume p 3 end
EM.run do
fiber = Fiber.new do current_fiber = Fiber.current p 1 res = EventMachine::HttpRequest.new("https://www.ruby-lang.org/").aget res.callback { p 4; current_fiber.resume(5) } p 2 puts Fiber.yield p 6 end p 0 fiber.resume p 3 end
EM.run do
fiber = Fiber.new do current_fiber = Fiber.current p 1 res = EventMachine::HttpRequest.new("https://www.ruby-lang.org/").aget res.callback { p 4; current_fiber.resume(5) } p 2 puts Fiber.yield p 6 end p 0 fiber.resume p 3
end
_UpdateTime(); _RunTimers();
_AddNewDescriptors(); _ModifyDescriptors();
_RunEpollOnce();
_DispatchHeartbeats(); _CleanupSockets();
if (bTerminateSignalReceived) return false;
_UpdateTime(); _RunTimers();
_AddNewDescriptors();_ModifyDescriptors();
_RunEpollOnce();
_DispatchHeartbeats(); _CleanupSockets();
if (bTerminateSignalReceived) return false;
_UpdateTime(); _RunTimers();
_AddNewDescriptors(); _ModifyDescriptors();
_RunEpollOnce();
_DispatchHeartbeats(); _CleanupSockets();
if (bTerminateSignalReceived) return false;
EM.run do
fiber = Fiber.new do current_fiber = Fiber.current p 1 res = EventMachine::HttpRequest.new("https://www.ruby-lang.org/").aget res.callback { p 4; current_fiber.resume(5) } p 2 puts Fiber.yield p 6 end p 0 fiber.resume p 3 end
EM.run do
fiber = Fiber.new do current_fiber = Fiber.current p 1 res = EventMachine::HttpRequest.new("https://www.ruby-lang.org/").aget res.callback { p 4; current_fiber.resume(5) } p 2 puts Fiber.yield p 6 end p 0 fiber.resume p 3 end
EM.run do
fiber = Fiber.new do current_fiber = Fiber.current p 1 res = EventMachine::HttpRequest.new("https://www.ruby-lang.org/").aget res.callback { p 4; current_fiber.resume(5) } p 2 puts Fiber.yield p 6 end p 0 fiber.resume p 3 end
EM.run do
fiber = Fiber.new do current_fiber = Fiber.current p 1 res = EventMachine::HttpRequest.new("https://www.ruby-lang.org/").aget res.callback { p 4; current_fiber.resume(5) } p 2 puts Fiber.yield p 6 end p 0 fiber.resume p 3 end
enumerator = Fiber.new do val = 0
loop do val += 1 Fiber.yield(val) end end
enumerator.resume # => 1 enumerator.resume # => 2 enumerator.resume # => 3