ruby reuses native os threads after ruby threads die
Since Ruby 1.9, each Ruby Thread
gets executed on its own native operating system thread.
But, as a performance optimization, Ruby will try to reuse native operating system threads if it can.
When a Ruby Thread
terminates, Ruby will not immediately terminate the operating system thread that was hosting it. Instead, it will keep it around for a few seconds, and if in that time period the application starts a new Thread
, then Ruby will reuse an existing operating system thread.
This can be observed on Ruby 3.1+ by using the new Thread#native_thread_id
method:
puts RUBY_DESCRIPTION
def thread_info
"Thread #{Thread.current} is being hosted by #{Thread.current.native_thread_id}"
end
puts Thread.new { thread_info }.value
puts Thread.new { thread_info }.value
puts Thread.new { thread_info }.value
puts "Sleeping for a bit..."
sleep 10
puts Thread.new { thread_info }.value
…and here’s the result of running this example:
ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [x86_64-linux] Thread #<Thread:0x00007f0e5e985030 example1.rb:7 run> is being hosted by 44061 Thread #<Thread:0x00007f0e5e9841a8 example1.rb:8 run> is being hosted by 44061 Thread #<Thread:0x00007f0e5e98bcc8 example1.rb:9 run> is being hosted by 44061 Sleeping for a bit... Thread #<Thread:0x00007f0e5e98b070 example1.rb:14 run> is being hosted by 44084
On older Rubies, Thread#native_thread_id
did not not exist yet, but we can implement our own:
puts RUBY_DESCRIPTION
# Only for Linux; supporting other OS's is left as an exercise for the reader ;)
def current_native_thread_id
File.readlink("/proc/thread-self").split("/").last
end
def thread_info
"Thread #{Thread.current} is being hosted by #{current_native_thread_id}"
end
puts Thread.new { thread_info }.value
puts Thread.new { thread_info }.value
puts Thread.new { thread_info }.value
puts "Sleeping for a bit..."
sleep 10
puts Thread.new { thread_info }.value
…and here’s the result of running this example on the older Ruby 2.7 series:
ruby 2.7.2p137 (2020-10-01 revision 5445e04352) [x86_64-linux] Thread #<Thread:0x0000564a32b02110 example2.rb:12 run> is being hosted by 45998 Thread #<Thread:0x0000564a32afbdb0 example2.rb:13 run> is being hosted by 45998 Thread #<Thread:0x0000564a32af9f38 example2.rb:14 run> is being hosted by 45998 Sleeping for a bit... Thread #<Thread:0x0000564a32af7e90 example2.rb:19 run> is being hosted by 46002
I hope you found this Ruby tidbit interesting!