我们都知道,一个程序可能有多个进程组成,而一个进程也可以有多个线程并行运行。线程的并行运行,可以提高程序的运行效率,但也存在着很多的危险,可能出现多个线程抢占一个资源的情况。这里我们就以ruby为例来说一说线程在ruby当中的应用。
我们先从一个简单的程序开始,程序实现一个并行对不同网站发送请求的过程。代码如下所示:
require 'net/http'
pages = %w(www.iteye.com www.csdn.net www.sina.com.cn www.google.cn)
threads = []
for page in pages
threads << Thread.new(page) do |url|
h = Net::HTTP.new(url, 80)
puts "The URL is #{url} "
resp = h.get('/', nil)
puts "The #{url} response : #{resp.message}"
end
end
threads.each { |t|t.join }
该段程序引用自Programming Ruby当中,程序中提供了一个网站列表数组,然后并发的从数组当中请求相应的网站。可能有些人对%w有些迷惑,%w会自动的对括号后面的字符串以空格进行分割,保存在数组当中。怎么样,ruby很sex吧,省去了很多的“”的困扰了。
我们通过Thread.new来创建线程。我们将网站列表当中的地址作为参数传递给线程。这里有个问题就是我们为什么不把地址直接传递给block(net)呢。这里就牵扯到了线程的全局变量和局部变量的概念了。试想一下,如果我们把地址直接传递给net模块,那么如果在线程1没有执行完成的时候,线程2启动了,重新给page赋值,此时的线程1还在使用page。错误这个时候就会产生了,往往这种错误在线程并行当中很难发现。我们所做的就是将变量私有化给线程。这里我们将每个传递给线程的变量私有化未url,只在当前线程当中有效。这样就很好的解决了线程之间的一个全局变量共享的问题。
threads.each { |t|t.join }
大家可能注意到这段代码了,在ruby当中,当程序终止的时候,不管线程状态如何,所有的线程都会被杀死。我们调用Thread#join方法用来等待特定的线程结束。调用join的线程会阻塞,直到指定线程结束,所以对所有线程执行join操作,可以保证在程序结束前执行完所有的线程。
上面提到了,线程可以有其私有变量,线程的私有变量在线程创建的时候写入线程。可以被线程范围内使用,但是不能被线程外部进行共享。但是有时候,线程的局部变量需要别别的线程或者主线程访问怎么办?ruby当中提供了允许通过名字来创建线程变量,类似的把线程看做hash式的散列表。通过[]=写入并通过[]读出数据。我们来看一下下面的代码:
# 线程变量
count = 0
threads =[]
10.times do |i|
threads[i] = Thread.new do
sleep(rand(0.1))
Thread.current["myvalue"] =count #将值赋给当前变量
count += 1
end
end
threads.each { |t| t.join; puts t["myvalue"] }
我们和前面的程序一样,分别创建10个线程,并将值赋值给当前线程,用myvalue进行标识,最后我们在线程外部可以通过myvalue标示对数据进行读取。 好吧,线程的第一步就说到这里把。明天继续