ruby中并发并行与全局锁详解

2019-09-25 09:36:03于海丽

前言

本文主要给大家介绍了关于ruby并发并行和全局锁的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧。

并发和并行

在开发时,我们经常会接触到两个概念: 并发和并行,几乎所有谈到并发和并行的文章都会提到一点: 并发并不等于并行.那么如何理解这句话呢?

并发: 厨师同时接收到了2个客人点了的菜单需要处理. 顺序执行: 如果只有一个厨师,那么他只能一个菜单接着一个菜单的去完成. 并行执行: 如果有两个厨师,那么就可以并行,两个人一起做菜.

将这个例子扩展到我们的web开发中, 就可以这样理解:

并发:服务器同时收到了两个客户端发起的请求. 顺序执行:服务器只有一个进程(线程)处理请求,完成了第一个请求才能完成第二个请求,所以第二个请求就需要等待. 并行执行:服务器有两个进程(线程)处理请求,两个请求都能得到响应,而不存在先后的问题.

根据上述所描述的例子,我们在 ruby 中怎么去模拟出这样的一个并发行为呢? 看下面这一段代码:

1、顺序执行:

模拟只有一个线程时的操作.

require 'benchmark'

def f1
 puts "sleep 3 seconds in f1n"
 sleep 3
end

def f2
 puts "sleep 2 seconds in f2n"
 sleep 2 
end

Benchmark.bm do |b|
 b.report do
 f1
 f2
 end 
end
## 
## user  system  total  real
## sleep 3 seconds in f1
## sleep 2 seconds in f2
## 0.000000 0.000000 0.000000 ( 5.009620)

上述代码很简单,用 sleep 模拟耗时的操作.顺序执行时候的消耗时间.

2、并行执行

模拟多线程时的操作

# 接上述代码
Benchmark.bm do |b|
 b.report do
 threads = []
 threads << Thread.new { f1 }
 threads << Thread.new { f2 }
 threads.each(&:join)
 end 
end
##
## user  system  total  real
## sleep 3 seconds in f1
## sleep 2 seconds in f2
## 0.000000 0.000000 0.000000 ( 3.005115)

我们发现多线程下耗时和f1的耗时相近,这与我们预期的一样,采用多线程可以实现并行.

Ruby 的多线程能够应付 IO Block,当某个线程处于 IO Block 状态时,其它的线程还可以继续执行,从而使整体处理时间大幅缩短.

Ruby 中的线程

上述的代码示例中使用了 ruby 中 Thread 的线程类, Ruby可以很容易地写Thread类的多线程程序.Ruby线程是一个轻量级的和有效的方式,以实现在你的代码的并行.

接下来来描述一段并发时的情景

 def thread_test
 time = Time.now
 threads = 3.times.map do 
  Thread.new do
  sleep 3 
  end
 end
 puts "不用等3秒就可以看到我:#{Time.now - time}"
 threads.map(&:join)
 puts "现在需要等3秒才可以看到我:#{Time.now - time}"
 end
 test
 ## 不用等3秒就可以看到我:8.6e-05
 ## 现在需要等3秒才可以看到我:3.003699