编程语言
首页 > 编程语言> > (18)Ruby使用Thread多线程

(18)Ruby使用Thread多线程

作者:互联网

Ruby 中提供 Thread 类来创建多线程

Ruby的线程是一个轻量级的,可以以高效的方式来实现并行的代码
要启动一个新的线程,只需要调用 Thread.new 即可:

一个正在系统上运行的程序都是一个进程。每个进程包含一到多个线程。
线程是程序中一个单一的顺序控制流程,在单个程序中同时运行多个线程完成不同的工作,称为多线程

核心:获取在线帮助Thread.methods

=> [:new, :start, :fork, :main, :current, :stop, :kill, :exit, :pass,  :list,
:exclusive,  :attr, :attr_reader, :attr_writer, :attr_accessor, :const_get, :const_set, :send, ]

事例如下:

# 线程 #1 代码部分
Thread.new {
 # 线程 #2 执行代码
}
# 线程 #1 执行代码

线程生命周期

线程和异常

当某线程发生异常,且没有被rescue捕捉到时,该线程通常会被无警告地终止。但是,
若有其它线程因为Thread#join的关系一直等待该线程的话,则等待的线程同样会被引发相同的异常。

线程同步控制

在Ruby中,提供三种实现同步的方式,分别是:

  1. 通过Mutex类实现线程同步
  2. 监管数据交接的Queue类实现线程同步
  3. 使用ConditionVariable实现同步控制

线程同步——通过Mutex类实现

通过Mutex类实现线程同步控制,如果在多个线程钟同时需要一个程序变量,
可以将这个变量部分使用lock锁定。

线程同步——监管数据交接的Queue类实现

Queue类就是表示一个支持线程的队列,能够同步对队列末尾进行访问。不同的线程可以使用统一个对类
但是不用担心这个队列中的数据是否能够同步,另外使用SizedQueue类能够限制队列的长度
SizedQueue类能够非常便捷的帮助我们开发线程同步的应用程序,应为只要加入到这个队列中
就不用关心线程的同步问题。

经典的生产者消费者问题:

线程变量

线程可以有其私有变量,线程的私有变量在线程创建的时候写入线程。
可以被线程范围内使用,但是不能被线程外部进行共享。

但是有时候,线程的局部变量需要别别的线程或者主线程访问怎么办?
ruby当中提供了允许通过名字来创建线程变量,

类似的把线程看做hash式的散列表。通过[]=写入并通过[]读出数据。

线程优先级

线程的优先级是影响线程的调度的主要因素。其他因素包括占用CPU的执行时间长短,线程分组调度等等。
可以使用 Thread.priority 方法得到线程的优先级和使用 Thread.priority= 方法来调整线程的优先级。
线程的优先级默认为 0 。 优先级较高的执行的要快。

Thread 类提供了线程数据互相访问的方法
一个 Thread 可以访问自己作用域内的所有数据,但如果有需要在某个线程内访问其他线程的数据应该怎么做呢?
你可以简单的把一个线程作为一个 Hash 表,可以在任何线程内使用 []= 写入数据,使用 [] 读出数据。

athr = Thread.new { Thread.current["name"] = "Thread A"; Thread.stop }
bthr = Thread.new { Thread.current["name"] = "Thread B"; Thread.stop }
cthr = Thread.new { Thread.current["name"] = "Thread C"; Thread.stop }
Thread.list.each {|x| puts "#{x.inspect}: #{x["name"]}" }

线程互斥

Mutex(Mutal Exclusion = 互斥锁)是一种用于多线程编程中
防止两条线程同时对同一公共资源(比如全局变量)进行读写的机制

线程死锁

两个以上的运算单元,双方都在等待对方停止运行,以获取系统资源,但是没有一方提前退出时.
这种状况,就称为死锁。例如,一个进程 p1占用了显示器,同时又必须使用打印机,
而打印机被进程p2占用,p2又必须使用显示器,这样就形成了死锁。

当我们在使用 Mutex 对象时需要注意线程死锁。

线程类方法

完整的 Thread(线程) 类方法如下:

1) Thread.new( [ arg ]* ) {| args | block }

生成线程,并开始执行。 数据会被原封不动地传递给块.
这就可以在启动线程的同时, 将值传递给该线程所固有的局部变量。

2) Thread.start( [ args ]* ) {| args | block }

生成线程,并开始执行。数据会被原封不动地传递给块.
这就可以在启动线程的同时,将值传递给该线程所固有的局部变量。

3) Thread.fork { block }

与 Thread.new 一样生成线程,是上面两种方式的变种;为了适应进程创建的习惯;

4) Thread.exit

终止当前线程的运行。返回当前线程。若当前线程是唯一的一个线程时,将使用exit(0)来终止它的运行

5) Thread.kill( aThread )

终止线程的运行.

6) Thread.stop

将当前线程挂起,直到其他线程使用run方法再次唤醒该线程

7) Thread.list

返回处于运行状态或挂起状态的活线程的数组。

8) Thread.abort_on_exception

若其值为真的话,一旦某线程因异常而终止时,整个解释器就会被中断。它的默认值是假,也就是说,
在通常情况下,若某线程发生异常且该异常未被Thread#join等检测到时,该线程会被无警告地终止。

9) Thread.abort_on_exception=

如果设置为 true, 一旦某线程因异常而终止时,整个解释器就会被中断。返回新的状态

10) Thread.critical

返回布尔值。

11) Thread.critical=

当其值为true时,将不会进行线程切换。若当前线程挂起(stop)或有信号(signal)干预时,其值将自动变为false。

12) Thread.current

返回当前运行中的线程(当前线程)。

13) Thread.main

返回主线程。

14) Thread.pass

将运行权交给其他线程. 它不会改变运行中的线程的状态,而是将控制权交给其他可运行的线程(显式的线程调度)。

线程实例化方法,以下是完整实例化方法列表:

1) thr[ name ]

取出线程内与name相对应的固有数据。 name可以是字符串或符号。 若没有与name相对应的数据时, 返回nil。

2) thr[ name ] =

设置线程内name相对应的固有数据的值, name可以是字符串或符号。 若设为nil时, 将删除该线程内对应数据。

3) thr.abort_on_exception

返回布尔值。

4) thr.abort_on_exception=

若其值为true的话,一旦某线程因异常而终止时,整个解释器就会被中断。

5) thr.alive?

若线程是"活"的,就返回true。

6) thr.exit

终止线程的运行。返回self。

7) thr.join

挂起当前线程,直到self线程终止运行为止. 若self因异常而终止时, 将会当前线程引发同样的异常。

8) thr.key?

若与name相对应的线程固有数据已经被定义的话,就返回true

9) thr.kill

类似于 Thread.exit 。

10) thr.priority

返回线程的优先度. 优先度的默认值为0. 该值越大则优先度越高.

11) thr.priority=

设定线程的优先度. 也可以将其设定为负数.

12) thr.raise( anException )

在该线程内强行引发异常.

13) thr.run

重新启动被挂起(stop)的线程. 与wakeup不同的是,它将立即进行线程的切换.
若对死进程使用该方法时, 将引发ThreadError异常.

14) thr.safe_level

返回self 的安全等级. 当前线程的safe_level与$SAFE相同.

15) thr.status

使用字符串"run"、"sleep"或"aborting" 来表示活线程的状态.
若某线程是正常终止的话,就返回false. 若因异常而终止的话,就返回nil。

16) thr.stop?

若线程处于终止状态(dead)或被挂起(stop)时,返回true.

17) thr.value

一直等到self线程终止运行(等同于join)后,返回该线程的块的返回值.
若在线程的运行过程中发生了异常, 就会再次引发该异常.

18) thr.wakeup

把被挂起(stop)的线程的状态改为可执行状态(run), 若对死线程执行该方法时,将会引发ThreadError异常。

标签:返回,name,Thread,18,thr,线程,new,多线程,Ruby
来源: https://blog.51cto.com/rulix9527/2842982