Is there some way to run 2 threads at the same time?
I want to have my app run its current function and then bring up another threa开发者_开发知识库d running another function, that can change variables in the first thread.
If you want to run two threads at the same time, the entire execution stack has to be capable of doing that. Let's start at the top:
- Ruby itself is capable of running two threads at the same time, no problem there. However, Ruby is just a programming language, i.e. just a bunch of rules. In order to run your program, you need a Ruby implementation. Unfortunately, many popular Ruby implementations are not capable of running multiple threads at the same time, including MRI, YARV and Rubinius. In fact, the only production-ready Ruby implementation which can run threads simultaneously is JRuby. (IronRuby too, but that is technically not yet production-ready although the final 1.0 release is probably only days away.)
- But JRuby (and IronRuby) don't actually implement threads themselves, they just use the underlying platform's threads. I.e. JRuby maps Ruby threads to JVM threads and IronRuby maps them to CLI threads. So, the underlying platform has to be able to run threads in parallel, too.
- Again: both the JVM and the CLI are in principle capable of running threads in parallel, but the JVM and the CLI are just specifications, they are just pieces of paper. In order to run your code, you need an implementation of those specifications, and not all of them do support truly concurrent threads.
- Even if your platform implementation supports truly concurrent threads, they might themselves delegate their threading implementation to the underlying OS, just like JRuby delegates to the JVM. .NET, Mono, HotSpot and JRockit for example (which are the most popular implementations of the CLI and the JVM respectively) use native OS threads for their platform threads. So, obviously, the OS has to be able to run threads in parallel. And again: not all of them are.
- And, of course, all the parallelism in the OS doesn't help if you only have one CPU. If you want two threads to run at the same time, you need either two CPUs, two cores or two simultaneous hardware threads.
http://ruby-doc.org/core/classes/Thread.html
x = 2
Thread.new do
x = 3
end
x = 4
For true concurrency having more then 2 cores or 2 processors is required - but it may not work if implementation is single-threaded (such as the MRI).
First, I'm gonna answer your question:
thread_1 = Thread.new do
#do something here
end
thread_2 = Thread.new do
#do something here
end
thread_1.join
thread_2.join(timeout_in_seconds)
Thread#join
makes the main thread to wait until the joined thread finishes. If you specify a timeout in seconds, Ruby will close the thread after that timeout is reached.
Now, the truth, there's no real concurrency in ruby 1.8 with the Matz Ruby Interpreter (MRI) and there's no real concurrency with only one processor though. According to this page:
However, as part of this runtime, the interpreter also instantiates an instance of a Global Interpreter Lock (or more affectionately known as GIL), which is the culprit of our lack of concurrency
Read the article itself for more information.
The MRI tries to cheat you using what's called Green Threads, which means that the Ruby interpreter takes care of everything to do with threads, not the OS, the other kind of threads, the ones really concurrent are called native threads and Ruby 1.9 support them through YARV but it doesn't mean that every Ruby thread runs in parallel because YARV has global VM lock (global interpreter lock or GIL) so concurrency is a myth in ruby and it'll be for a long time.
http://ruby-doc.org/core/classes/Thread.html
Remember that only in JRuby threads are truly parallel (other interpreters implement GIL). From here:
# mutexsyncex.rb
require 'thread' # For Mutex class in Ruby 1.8
# A BankAccount has a name, a checking amount, and a savings amount
class BankAccount
def initialize(name, checking, savings)
@name,@checking,@savings = name,checking,savings
@lock = Mutex.new # For thread safety
end
# Lock account and transfer money from savings to checking
def transfer_from_savings(x)
@lock.synchronize {
@savings -= x
@checking += x
}
end
# Lock account and report current balances
def report
@lock.synchronize {
"#@name\nChecking: #@checking\nSavings: #@savings"
}
end
end
ba = BankAccount.new('me', 1, 400)
ba.transfer_from_savings(10);
puts ba.report
精彩评论