Ruby 多线程探索实践与归纳总结
Ruby 多线程
每个正在系统上运行的程序都是一个进程。每个进程包含一到多个线程。
线程是程序中一个单一的顺序控制流程,在单个程序中同时运行多个线程完成不同的工作,称为多线程。
Ruby 中我们可以通过 Thread 类来创建多线程,Ruby的线程是一个轻量级的,可以以高效的方式来实现并行的代码。
创建 Ruby 线程
要启动一个新的线程,只需要调用 Thread.new 即可:
# 线程 #1 代码部分
Thread.new {
# 线程 #2 执行代码
}
# 线程 #1 执行代码
实例
以下实例展示了如何在Ruby程序中使用多线程:
#!/usr/bin/ruby def func1
i=
while i<=
puts "func1 at: #{Time.now}"
sleep()
i=i+
end
end def func2
j=
while j<=
puts "func2 at: #{Time.now}"
sleep()
j=j+
end
end puts "Started At #{Time.now}"
t1=Thread.new{func1()}
t2=Thread.new{func2()}
t1.join
t2.join
puts "End at #{Time.now}"
以上代码执行结果为:
Started At Wed May :: -
func1 at: Wed May :: -
func2 at: Wed May :: -
func2 at: Wed May :: -
func1 at: Wed May :: -
func2 at: Wed May :: -
func1 at: Wed May :: -
End at Wed May :: -
线程生命周期
1、线程的创建可以使用Thread.new,同样可以以同样的语法使用Thread.start 或者Thread.fork这三个方法来创建线程。
2、创建线程后无需启动,线程会自动执行。
3、Thread 类定义了一些方法来操控线程。线程执行Thread.new中的代码块。
4、线程代码块中最后一个语句是线程的值,可以通过线程的方法来调用,如果线程执行完毕,则返回线程值,否则不返回值直到线程执行完毕。
5、Thread.current 方法返回表示当前线程的对象。 Thread.main 方法返回主线程。
6、通过 Thread.Join 方法来执行线程,这个方法会挂起主线程,直到当前线程执行完毕。
线程状态
线程有5种状态:
| 线程状态 | 返回值 |
|---|---|
| Runnable | run |
| Sleeping | Sleeping |
| Aborting | aborting |
| Terminated normally | false |
| Terminated with exception | nil |
线程和异常
当某线程发生异常,且没有被rescue捕捉到时,该线程通常会被无警告地终止。但是,若有其它线程因为Thread#join的关系一直等待该线程的话,则等待的线程同样会被引发相同的异常。
begin
t = Thread.new do
Thread.pass # 主线程确实在等join
raise "unhandled exception"
end
t.join
rescue
p $! # => "unhandled exception"
end
使用下列3个方法,就可以让解释器在某个线程因异常而终止时中断运行。
- 启动脚本时指定-d选项,并以调试模时运行。
- 用
Thread.abort_on_exception设置标志。 - 使用
Thread#abort_on_exception对指定的线程设定标志。
当使用上述3种方法之一后,整个解释器就会被中断。
t = Thread.new { ... }
t.abort_on_exception = true
线程同步控制
在Ruby中,提供三种实现同步的方式,分别是:
1. 通过Mutex类实现线程同步
2. 监管数据交接的Queue类实现线程同步
3. 使用ConditionVariable实现同步控制
通过Mutex类实现线程同步
通过Mutex类实现线程同步控制,如果在多个线程钟同时需要一个程序变量,可以将这个变量部分使用lock锁定。 代码如下:
#encoding:gbk
require "thread"
puts "Synchronize Thread" @num=
@mutex=Mutex.new def buyTicket(num)
@mutex.lock
if @num>=num
@num=@num-num
puts "you have successfully bought #{num} tickets"
else
puts "sorry,no enough tickets"
end
@mutex.unlock
end ticket1=Thread.new do
.times do |value|
ticketNum=
buyTicket(ticketNum)
sleep 0.01
end
end ticket2=Thread.new do
.times do |value|
ticketNum=
buyTicket(ticketNum)
sleep 0.01
end
end sleep
ticket1.join
ticket2.join
输出结果如下:
Synchronize Thread
you have successfully bought tickets
you have successfully bought tickets
you have successfully bought tickets
you have successfully bought tickets
you have successfully bought tickets
you have successfully bought tickets
you have successfully bought tickets
you have successfully bought tickets
you have successfully bought tickets
you have successfully bought tickets
you have successfully bought tickets
sorry,no enough tickets
sorry,no enough tickets
sorry,no enough tickets
sorry,no enough tickets
sorry,no enough tickets
sorry,no enough tickets
sorry,no enough tickets
sorry,no enough tickets
sorry,no enough tickets
除了使用lock锁定变量,还可以使用try_lock锁定变量,还可以使用Mutex.synchronize同步对某一个变量的访问。
监管数据交接的Queue类实现线程同步
Queue类就是表示一个支持线程的队列,能够同步对队列末尾进行访问。不同的线程可以使用统一个对类,但是不用担心这个队列中的数据是否能够同步,另外使用SizedQueue类能够限制队列的长度
SizedQueue类能够非常便捷的帮助我们开发线程同步的应用程序,应为只要加入到这个队列中,就不用关心线程的同步问题。
经典的生产者消费者问题:
#encoding:gbk
require "thread"
puts "SizedQuee Test" queue = Queue.new producer = Thread.new do
.times do |i|
sleep rand(i) # 让线程睡眠一段时间
queue << i
puts "#{i} produced"
end
end consumer = Thread.new do
.times do |i|
value = queue.pop
sleep rand(i/)
puts "consumed #{value}"
end
end consumer.join
程序的输出: SizedQuee Test
produced
produced
consumed
produced
consumed
consumed
produced
consumed produced consumed
produced
consumed
produced
consumed
produced
consumed
produced
produced
consumed
consumed
使用ConditionVariable实现同步控制
使用 ConditonVariable进行同步控制,能够在一些致命的资源竞争部分挂起线程直到有可用的资源为止。
#encoding:gbk
require "thread"
puts "thread synchronize by ConditionVariable" mutex = Mutex.new
resource = ConditionVariable.new a = Thread.new {
mutex.synchronize {
# 这个线程目前需要resource这个资源
resource.wait(mutex)
puts "get resource"
}
} b = Thread.new {
mutex.synchronize {
#线程b完成对resourece资源的使用并释放resource
resource.signal
}
} a.join
puts "complete"
mutex 是声明的一个资源,然后通过ConditionVariable来控制申请和释放这个资源。
b 线程完成了某些工作之后释放资源resource.signal,这样a线程就可以获得一个mutex资源然后进行执行。 执行结果:
thread synchronize by ConditionVariable get resource complete
线程类方法
完整的 Thread(线程) 类方法如下:
| 序号 | 方法描述 |
|---|---|
| 1 | Thread.abort_on_exception 若其值为真的话,一旦某线程因异常而终止时,整个解释器就会被中断。它的默认值是假,也就是说,在通常情况下,若某线程发生异常且该异常未被Thread#join等检测到时,该线程会被无警告地终止。 |
| 2 | Thread.abort_on_exception= 如果设置为 true, 一旦某线程因异常而终止时,整个解释器就会被中断。返回新的状态 |
| 3 | Thread.critical 返回布尔值。 |
| 4 | Thread.critical= 当其值为true时,将不会进行线程切换。若当前线程挂起(stop)或有信号(signal)干预时,其值将自动变为false。 |
| 5 | Thread.current 返回当前运行中的线程(当前线程)。 |
| 6 | Thread.exit 终止当前线程的运行。返回当前线程。若当前线程是唯一的一个线程时,将使用exit(0)来终止它的运行。 |
| 7 | Thread.fork { block } 与 Thread.new 一样生成线程。 |
| 8 | Thread.kill( aThread ) 终止线程的运行. |
| 9 | Thread.list 返回处于运行状态或挂起状态的活线程的数组。 |
| 10 | Thread.main 返回主线程。 |
| 11 | Thread.new( [ arg ]* ) {| args | block } 生成线程,并开始执行。数会被原封不动地传递给块. 这就可以在启动线程的同时,将值传递给该线程所固有的局部变量。 |
| 12 | Thread.pass 将运行权交给其他线程. 它不会改变运行中的线程的状态,而是将控制权交给其他可运行的线程(显式的线程调度)。 |
| 13 | Thread.start( [ args ]* ) {| args | block } 生成线程,并开始执行。数会被原封不动地传递给块. 这就可以在启动线程的同时,将值传递给该线程所固有的局部变量。 |
| 14 | Thread.stop 将当前线程挂起,直到其他线程使用run方法再次唤醒该线程。 |
线程实例化方法
以下实例调用了线程实例化方法 join:
#!/usr/bin/ruby thr = Thread.new do # 实例化
puts "In second thread"
raise "Raise exception"
end
thr.join # 调用实例化方法 join
以下是完整实例化方法列表:
| 序号 | 方法描述 |
|---|---|
| 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异常 |
作为新接触的Ruby新手,不足之处,还请各位大神指点...
![]() |
本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须且在文章页面明显位置给出原文链接Dana、Li(包含链接),具体操作方式可参考此处。如您有任何疑问或者授权方面的协商,请留言或加Q群!
|
Ruby 多线程探索实践与归纳总结的更多相关文章
- 【Scala】Scala多线程-并发实践
Scala多线程-并发实践 scala extends Thread_百度搜索 scala多线程 - 且穷且独立 - 博客园 Scala和并发编程 - Andy Tech Talk - ITeye博客 ...
- 雷林鹏分享:Ruby 多线程
Ruby 多线程 每个正在系统上运行的程序都是一个进程.每个进程包含一到多个线程. 线程是程序中一个单一的顺序控制流程,在单个程序中同时运行多个线程完成不同的工作,称为多线程. Ruby 中我们可以通 ...
- 基于 Apache Hudi 极致查询优化的探索实践
摘要:本文主要介绍 Presto 如何更好的利用 Hudi 的数据布局.索引信息来加速点查性能. 本文分享自华为云社区<华为云基于 Apache Hudi 极致查询优化的探索实践!>,作者 ...
- WOT干货大放送:大数据架构发展趋势及探索实践分享
WOT大数据处理技术分会场,PingCAP CTO黄东旭.易观智库CTO郭炜.Mob开发者服务平台技术副总监林荣波.宜信技术研发中心高级架构师王东及商助科技(99Click)顾问总监郑泉五位讲师, ...
- SQLite多线程读写实践及常见问题总结
多线程读写 SQLite实质上是将数据写入一个文件,通常情况下,在应用的包名下面都能找到xxx.db的文件,拥有root权限的手机,可以通过adb shell,看到data/data/packagen ...
- python3和grpc的微服务探索实践
对于微服务的实践,一般都是基于Java和Golang的,博主最近研究了下基于Python的微服务实践,现在通过一个简单的服务来分析Python技术栈的微服务实践 技术栈:Python3 + grpc ...
- python 多线程探索
前面已经了解过了,python多线程效率较低的主要原因是存在GIL,即Global Interpreter Lock(全局解释器锁).这里继续详细的看下GIL的说明与如何避免GIL的影响,从而提高py ...
- zz阿里妈妈深度树检索技术(TDM)及应用框架的探索实践
分享嘉宾:何杰 阿里妈妈 高级算法专家 编辑整理:孙锴 内容来源:DataFun AI Talk 出品社区:DataFun 注:欢迎转载,转载请注明出处 导读:阿里妈妈是阿里巴巴集团旗下数字营销的大中 ...
- Java编程技巧:if-else优化实践总结归纳
文/朱季谦 说实话,其实我很讨厌在代码里大量使用if-else,一是因为该类代码属于面向过程的,二嘛,则是会显得代码过于冗余.这篇笔记,主要记录一些自己在工作实践当中针对if-else的优化心得,将会 ...
随机推荐
- sqlite3里类似top的用法
sqlite3里类似top的用法 在sqlserver中使用top是很正常的,类似这样的语句: SELECT TOP 10 * FROM [index] ORDER BY id DESC; 但是很不幸 ...
- 设计模式-适配器模式(Adapter)
简介: 适配器模式在我看来是最无聊的一种模式,因为他根本不是一种新的创意模式,而是一种不得已而为之的模式.就算不学适配器模式,在具体应用场景中也会自然而然的想到这种解决方案. 张三在英国留学时买了个笔 ...
- 软件工程 speedsnail 冲刺3
2015-5-7 完成任务:环境崩溃,重新配置环境,学习了黑马android教学视频前6集: 遇到问题: 问题1 Error: Error parsing C:\Users\sam\.android\ ...
- IntelliJ IDEA 13破解(JRebel 5.6.3a破解)
首先安装IntelliJ 13,记得要下载Ultimate Edition版本,不然就不需要破解了.. 安装到本地,然后进行一些配置(这一步可以不要,但是考虑到以后换系统可以省事,推荐做) 打开{in ...
- 通过JAVA代码获取手机的一些基本信息(本机号码,SDK版本,系统版本,手机型号)
代码如下: package com.zzw.getPhoneInfos; import android.app.Activity; import android.content.Context; im ...
- IOS学习3
@property属性使用 copy:NSString strong: 一般对象 weak: UI空间 assign:基本数据类型 retain: (对象,先上述类型使用) id 万能指针. id缺点 ...
- JDBC基础一
JDBC:java database connectivity SUN公司提供的一套操作数据库的标准规范. JDBC与数据库驱动的关系:接口与实现的关系. JDBC规范(掌握四个核心对象): Driv ...
- 委托、匿名函数与Lambda表达式初步
(以下内容主要来自<C#本质论第三版>第十二章委托和Lambda表达式) 一.委托续 上上周五看了看委托,初步明白了其是个什么,如何定义并调用.上周五准备看Lambda表达式,结果发现C# ...
- jQuery学习笔记(5)--表单域获得焦点和失去焦点样式变化
<html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> &l ...
- 解决Unable to resolve superclass的问题
之前在GITHUB上看到大蛋的高级设置,昨晚于是就拿来编译.. 结果真是个悲伤的故事,放手机上居然运行不了,这种时候只能看LOG了! 看LOG得出的信息如下: - ::): threadid=: in ...
