Ruby多线程
传统程序中有一个执行线程,包括程序的语句或指令顺序执行,直到程序终止.
一个多线程程序中有多个执行线程。在每个线程中,语句顺序执行,但可parallel.on执行线程本身多核的CPU,例如。多个线程往往在一个单CPU的机器,不实际执行并行,但并行交错执行的线程模拟.
可以很容易地写Thread类的多线程程序。 Ruby线程是一个轻量级的和有效的方式,以实现在你的代码的并行.
创建Ruby线程:
要开始一个新的线程,只是关联与以Thread.new调用块。将创建一个新线程执行的代码块,并从Thread.new原来的线程将立即返回,并恢复执行的下一条语句:
# Thread #1 is running hereThread.new { # Thread #2 runs this code}# Thread #1 runs this code
例子:
这里是一个例子,它表明,我们可以使用多线程的Ruby程序.
#!/usr/bin/ruby# by www.yiibai.comdef func1 i=0 while i<=2 puts "func1 at: #{Time.now}" sleep(2) i=i+1 endenddef func2 j=0 while j<=2 puts "func2 at: #{Time.now}" sleep(1) j=j+1 endendputs "Started At #{Time.now}"t1=Thread.new{func1()}t2=Thread.new{func2()}t1.joint2.joinputs "End at #{Time.now}"
这将产生以下结果:
Press ENTER or type command to continueStarted At Wed May 14 08:21:54 -0700 2008func1 at: Wed May 14 08:21:54 -0700 2008func2 at: Wed May 14 08:21:54 -0700 2008func2 at: Wed May 14 08:21:55 -0700 2008func1 at: Wed May 14 08:21:56 -0700 2008func2 at: Wed May 14 08:21:56 -0700 2008func1 at: Wed May 14 08:21:58 -0700 2008End at Wed May 14 08:22:00 -0700 2008
线程的生命周期:
一个新的线程创建与Thread.new。您还可以使用同义词Thread.start和Thread.fork.
有没有必要启动后创建一个线程,它开始自动运行时,CPU资源成为可用。
Thread类定义了一些方法,查询和操纵线程运行时。线程运行在与调用Thread.new关联块中的代码,然后停止运行.在该块中的最后一个表达式的值是线程的值,可以通过调用Thread对象的值的方法获得。如果线程已经运行完毕,则该值马上返回线程的值。否则,值的方法块和不返回,直到该线程已完成.
类的方法Thread.current返回表示当前线程的Thread对象。这使得线程来操纵自己类方法返回的Thread对象代表主要thread.this. Thread.main是Ruby程序的开始,开始时的初始线程的执行.
你可以等待一个特定的线程通过调用该线程的Thread.join方法来完成。调用线程将阻塞,直到给定的线程完成.
线程和异常:
如果在主线程中,提出了一个异常没有被处理的任何地方,Ruby解释器打印一个消息,并退出。在主线程以外的线程,未处理的异常导致线程停止运行.
如果一个线程ţ退出,因为未处理的异常,而另一个线程s调用t.join或t.value,然后在T发生的异常提出在线程s.
如果Thread.abort_on_exception是假的,默认情况下,出现未处理的异常简单杀死(kill)当前线程和所有其余的继续运行.
如果你想在任何线程中任何未处理的异常导致退出该解释器,类方法Thread.abort_on_exception设置为true.
t = Thread.new { ... }t.abort_on_exception = true
线程变量:
一个线程可以正常访问,线程被创建时该范围是任何变量。一个线程块的局部变量是线程局部的,不共享.
Thread类提供一个特殊的功能,允许通过名字创建和访问线程局部变量。您只需把线程对象,就好像它是一个Hash,写入元素使用[]=读取他们回到使用[].
在这个例子中,每个线程都记录在一个关键mycount ThreadLocal变量变量计数当前值.
#!/usr/bin/ruby#by www.yiibai.comcount = 0arr = []10.times do |i| arr[i] = Thread.new { sleep(rand(0)/10.0) Thread.current["mycount"] = count count += 1 }endarr.each {|t| t.join; print t["mycount"], ", " }puts "count = #{count}"
这将产生以下结果:
8, 0, 3, 7, 2, 1, 6, 5, 4, 9, count = 10
主线程等待子线程完成,然后打印出每个捕获ofcount的值.
线程优先级:
影响线程调度的首要因素是线程的优先级:高优先级线程的低优先级线程之前预定。更确切地说,一个线程将只得到CPU时间,如果有没有更高优先级的线程等待运行.
你可以设置和查询与Ruby的Thread对象的优先级=和优先的优先级。新创建的线程开始创建它的线程的优先级相同。主线程在优先级0启动.
有没有办法设置一个线程的优先级之前开始运行。然而,一个线程可以提高或降低其作为第一项行动,它需要自己的优先级.
线程互斥:
如果两个线程共享相同的数据的访问,以及至少一个线程修改数据,你必须要特别小心,以确保没有线程所能看到的数据处于不一致的状态。这被称为线程互斥.
Mutex是一个类,它实现了一个简单的一些共享资源的互斥访问的信号锁定。也就是说,只有一个线程可以持有锁在一个给定的时间。其他线程可能会选择等待锁线,变为可用,或者可能干脆选择错误,指示立即得到锁不能使用.
通过将所有访问一个互斥的控制下共享数据,我们可以确保一致性和原子操作。让我们尝试的例子,第一个先不使用mutax而第二个使用mutax:
不使用Mutax例子:
#!/usr/bin/rubyrequire 'thread'count1 = count2 = 0difference = 0counter = Thread.new do loop do count1 += 1 count2 += 1 endendspy = Thread.new do loop do difference += (count1 - count2).abs endendsleep 1puts "count1 : #{count1}"puts "count2 : #{count2}"puts "difference : #{difference}"
这将产生以下结果:
count1 : 1583766count2 : 1583766difference : 637992
使用Mutax例子:
#!/usr/bin/rubyrequire 'thread'mutex = Mutex.newcount1 = count2 = 0difference = 0counter = Thread.new do loop do mutex.synchronize do count1 += 1 count2 += 1 end endendspy = Thread.new do loop do mutex.synchronize do difference += (count1 - count2).abs end endendsleep 1mutex.lockputs "count1 : #{count1}"puts "count2 : #{count2}"puts "difference : #{difference}"
这将产生以下结果:
count1 : 696591count2 : 696591difference : 0
处理死锁:
当我们开始使用互斥对象的线程排斥,我们必须小心地避免死锁。死锁条件时所发生的所有线程正在等待获取另一个线程持有的资源。因为所有的线程被阻塞,他们不能释放持有的锁。因为他们不能释放的锁,没有其他线程可以获取这些锁.
这是条件变量的图片来。条件变量是一个简单的相关资源和用于特定互斥锁的保护范围内的信号。当你需要的资源是不可用的,你等待一个条件变量。这一操作释放相应的互斥锁。当其他一些线程信号的资源是可用的,原来的线程来等待,同时恢复对临界区锁.
例子:
#!/usr/bin/rubyrequire 'thread'mutex = Mutex.newcv = ConditionVariable.newa = Thread.new { mutex.synchronize { puts "A: I have critical section, but will wait for cv" cv.wait(mutex) puts "A: I have critical section again! I rule! - by www.yiibai.com" }}puts "(Later, back at the ranch...)"b = Thread.new { mutex.synchronize { puts "B: Now I am critical, but am done with cv" cv.signal puts "B: I am still critical, finishing up" }}a.joinb.join
这将产生以下结果:
A: I have critical section, but will wait for cv(Later, back at the ranch...)B: Now I am critical, but am done with cvB: I am still critical, finishing upA: I have critical section again! I rule!
线程状态:
有五个可能的返回值相应的5个可能的状态如下表所示。status方法返回线程的状态.
Thread state | Return value |
---|---|
Runnable | run |
Sleeping | Sleeping |
Aborting | aborting |
Terminated normally | false |
Terminated with exception | nil |
线程类方法:
Thread类提供下列方法和适用程序中提供的所有线程。这些方法将被调用Thread类的名称,使用如下:
Thread.abort_on_exception = true
这里是所有类方法的完整列表:
SN | Methods with Description |
---|---|
1 | Thread.abort_on_exceptionReturns the status of the global abort on exception condition. The default is false. When set to true, will cause all threads to abort (the process will exit(0)) if an exception is raised in any thread. |
2 | Thread.abort_on_exception=When set to true, all threads will abort if an exception is raised. Returns the new state. |
3 | Thread.criticalReturns the status of the global thread critical condition. |
4 | Thread.critical=Sets the status of the global thread critical condition and returns it. When set totrue, prohibits scheduling of any existing thread. Does not block new threads from being created and run. Certain thread operations (such as stopping or killing a thread, sleeping in the current thread, and raising an exception) may cause a thread to be scheduled even when in a critical section. |
5 | Thread.currentReturns the currently executing thread. |
6 | Thread.exitTerminates the currently running thread and schedules another thread to be run. If this thread is already marked to be killed, exit returns the Thread. If this is the main thread, or the last thread, exit the process. |
7 | Thread.fork { block }Synonym for Thread.new . |
8 | Thread.kill( aThread )Causes the given aThread to exit |
9 | Thread.listReturns an array of Thread objects for all threads that are either runnable or stopped. Thread. |
10 | Thread.mainReturns the main thread for the process. |
11 | Thread.new( [ arg ]* ) {| args | block }Creates a new thread to execute the instructions given in block, and begins running it. Any arguments passed to Thread.new are passed into the block. |
12 | Thread.passInvokes the thread scheduler to pass execution to another thread. |
13 | Thread.start( [ args ]* ) {| args | block }Basically the same as Thread.new . However, if class Thread is subclassed, then calling start in that subclass will not invoke the subclass's initialize method. |
14 | Thread.stopStops execution of the current thread, putting it into a sleep state, and schedules execution of another thread. Resets the critical condition to false. |
线程实例方法:
这些方法适用于线程的一个实例。这些方法将被称为使用如下线程的一个实例:
#!/usr/bin/rubythr = Thread.new do # Calling a class method new puts "In second thread" raise "Raise exception"endthr.join # Calling an instance method join
这里是所有的实例方法的完整列表:
SN | Methods with Description |
---|---|
1 | thr[ aSymbol ]Attribute Reference - Returns the value of a thread-local variable, using either a symbol or a aSymbol name. If the specified variable does not exist, returns nil. |
2 | thr[ aSymbol ] =Attribute Assignment - Sets or creates the value of a thread-local variable, using either a symbol or a string. |
3 | thr.abort_on_exceptionReturns the status of the abort on exception condition for thr. The default is false. |
4 | thr.abort_on_exception=When set to true, causes all threads (including the main program) to abort if an exception is raised in thr. The process will effectively exit(0). |
5 | thr.alive?Returns true if thr is running or sleeping. |
6 | thr.exitTerminates thr and schedules another thread to be run. If this thread is already marked to be killed, exit returns the Thread. If this is the main thread, or the last thread, exits the process. |
7 | thr.joinThe calling thread will suspend execution and run thr. Does not return until threxits. Any threads not joined will be killed when the main program exits. |
8 | thr.key?Returns true if the given string (or symbol) exists as a thread-local variable. |
9 | thr.killSynonym for Thread.exit . |
10 | thr.priorityReturns the priority of thr. Default is zero; higher-priority threads will run before lower priority threads. |
11 | thr.priority=Sets the priority of thr to an Integer. Higher-priority threads will run before lower priority threads. |
12 | thr.raise( anException )Raises an exception from thr. The caller does not have to be thr. |
13 | thr.runWakes up thr, making it eligible for scheduling. If not in a critical section, then invokes the scheduler. |
14 | thr.safe_levelReturns the safe level in effect for thr. |
15 | thr.statusReturns the status of thr: sleep if thr is sleeping or waiting on I/O, run if thr is executing, false if thr terminated normally, and nil if thr terminated with an exception. |
16 | thr.stop?Returns true if thr is dead or sleeping. |
17 | thr.valueWaits for thr to complete via Thread.join and returns its value. |
18 | thr.wakeupMarks thr as eligible for scheduling, it may still remain blocked on I/O, however. |