Potential and Weakness Analysis of Ruby multithreading, and ruby Multithreading

Source: Internet
Author: User

Potential and Weakness Analysis of Ruby multithreading, and ruby Multithreading

Most Web applications are IO-intensive. Using the Ruby multi-process + multi-thread model can greatly increase the system throughput. The reason is: when a Ruby thread is in the IO Block State, other threads can continue to execute. However, due to the existence of Ruby GIL (Global Interpreter Lock), MRI Ruby does not really use multithreading for parallel computing. In addition to GIL, JRuby is a true multi-thread. It can cope with IO blocks and make full use of multi-core CPUs to speed up the overall operation.

The above is abstract. The following examples are used to describe them one by one.

Ruby multithreading and IO Block

First look at the following code (demonstration purpose, no practical use ):
Copy codeThe Code is as follows:
# File: block_io1.rb

Def func1
Puts "sleep 3 seconds in func1 \ n"
Sleep (3)
End

Def func2
Puts "sleep 2 seconds in func2 \ n"
Sleep (2)
End

Def func3
Puts "sleep 5 seconds in func3 \ n"
Sleep (5)
End

Func1
Func2
Func3

The code is very simple. Three methods use sleep to simulate time-consuming IO operations. The result of running the code (Environment MRI Ruby 1.9.3) is:
Copy codeThe Code is as follows:
$ Time ruby block_io1.rb
Sleep 3 seconds in func1
Sleep 2 seconds in func2
Sleep 5 seconds in func3

Real 0m11. 681 s
User 0m3. 086 s
Sys 0m0. 152 s

The process is slow, and the time is spent on sleep. It takes more than 10 seconds in total.

Multithreading is adopted. Rewrite is as follows:
Copy codeThe Code is as follows:
# File: block_io2.rb

Def func1
Puts "sleep 3 seconds in func1 \ n"
Sleep (3)
End

Def func2
Puts "sleep 2 seconds in func2 \ n"
Sleep (2)
End

Def func3
Puts "sleep 5 seconds in func3 \ n"
Sleep (5)
End

Threads = []
Threads <Thread. new {func1}
Threads <Thread. new {func2}
Threads <Thread. new {func3}

Threads. each {| t. join}

The running result is:
Copy codeThe Code is as follows:
$ Time ruby block_io2.rb
Sleep 3 seconds in func1
Sleep 2 seconds in func2
Sleep 5 seconds in func3

Real 0m6. 543 s
User 0m3. 169 s
Sys 0m0. 147 s

It took more than 6 seconds in total, obviously much faster, just a little more than the longest sleep 5 seconds.

The preceding example shows that multiple threads in Ruby can cope with IO blocks. When a thread is in the I/O Block State, other threads can continue to execute, greatly shortening the overall processing time.


Ruby GIL impact

Let's take a look at a piece of code (demonstration purpose ):

Copy codeThe Code is as follows:
# File: gil1.rb

Require 'securerandom'
Require 'zlib'

Data = SecureRandom. hex (4096000)

16. times {Zlib: Deflate. deflate (data )}

The code first generates some random data and then compresses it. compression is very CPU-consuming. The running results on my machine (dual-core CPU, MRI Ruby 1.9.3) are as follows:
Copy codeThe Code is as follows:
$ Time ruby gil1.rb

Real 0m8. 572 s
User 0m8. 359 s
Sys 0m0. 102 s

The Code is as follows:
Copy codeThe Code is as follows:
# File: gil2.rb

Require 'securerandom'
Require 'zlib'

Data = SecureRandom. hex (4096000)

Threads = []
16. times do
Threads <Thread. new {Zlib: Deflate. deflate (data )}
End

Threads. each {| t. join}

The results of multi-threaded version running are as follows:
Copy codeThe Code is as follows:
$ Time ruby gil2.rb

Real 0m8. 616 s
User 0m8. 377 s
Sys 0m0. 211 s

From the results, we can see that due to the presence of MRI Ruby GIL, multiple threads in Ruby cannot reuse multi-core CPUs. The overall time spent after multithreading is not shortened, but due to the impact of thread switching, the amount of time has increased slightly.

Remove GIL from JRuby

Run gil1.rb and gil2.rb on JRuby (my machine is JRuby 1.7.0) and get different results.

Copy codeThe Code is as follows:
$ Time jruby gil1.rb

Real 0 M12. 225 s
User 0m14. 060 s
Sys 0m0. 615 s

Copy codeThe Code is as follows:
$ Time jruby gil2.rb

Real 0m7. 584 s
User 0m22. 822 s
Sys 0m0. 819 s

We can see that the overall running time of JRuby is significantly shortened (7.58 to 12.22) When multithreading is used. This is because JRuby removes GIL and can truly execute multiple threads in parallel, making full use of the multi-core CPU.

Conclusion: Ruby multithreading can still execute other threads in a thread IO Block to reduce the overall impact of IO Block. However, due to the presence of MRI Ruby GIL, MRI Ruby is not a real parallel execution. Without GIL, JRuby can achieve real multi-thread parallel execution.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.