Ruby的线程速度

时间:2011-08-11 13:53:18

标签: ruby multithreading file-io thread-safety

我有以下代码来线程安全写入文件:

threads = []
@@lock_flag = 0
@@write_flag = 0

def add_to_file
    old_i = 0
    File.open( "numbers.txt", "r" ) { |f| old_i = f.read.to_i }
    File.open( "numbers.txt", "w+") { |f| f.write(old_i+1) }
    #puts old_i
end

File.open( "numbers.txt", "w") { |f| f.write(0) } unless File.exist? ("numbers.txt")

2000.times do
    threads << Thread.new {
        done_flag = 0
        while done_flag == 0 do
            print "."           #### THIS LINE
            if @@lock_flag == 0
                @@lock_flag = 1
                if @@write_flag == 0
                    @@write_flag = 1
                    add_to_file
                    @@write_flag = 0
                    done_flag = 1
                end
                @@lock_flag = 0
            end
        end
    }
end

threads.each {|t| t.join}

如果我运行此代码,则将所有2000个数字写入文件大约需要1.5秒。所以一切都很好。 但如果我删除标有“THIS LINE”的行print "."需要很长时间!此代码大约需要12秒才能完成20个线程。

现在我的问题是:为什么print加速了这段代码呢?

2 个答案:

答案 0 :(得分:4)

我不确定如果根本不能将该线程称为安全线程。由于竞争条件,您无法使用简单变量来确保安全。测试标志为零并将其设置为1之间会发生什么?你根本就不知道。如果你不幸的话,任何事情都可以并且最终会在这个非常短暂的时间间隔内发生。

可能发生的事情是print语句导致线程停顿足够长的时间,导致破坏的锁定机制最终起作用。当使用Ruby 1.9.2测试该示例时,它甚至没有完成,看起来永远打印点。

您可能想尝试使用Mutex重写它:

write_mutex = Mutex.new
read_mutex = Mutex.new

2000.times do
    threads << Thread.new {
        done_flag = false
        while (!done_flag) do
            print "."           #### THIS LINE
            write_mutex.synchronize do
              read_mutex.synchronize do
                add_to_file
                done_flag = true
              end
            end
        end
    }
end

这是进行线程同步的正确Ruby方法。在确定您对其进行独占控制之前,Mutex不会产生锁定。还有try_lock方法会尝试抓取它,如果已经采用它将会失败。

线程可能是一个非常麻烦的事情,所以在使用它们时要非常小心。

答案 1 :(得分:0)

首先,有些宝石可以让这类事情变得更容易。 threachjruby_threach(“每个都有线程”)是我写的,虽然我对实现非常不满意,并且会在某些时候让它们变得更干净,但是当你在有安全的代码。

(1..100).threach(2) {|i| do_something_with(i)} # run method in two threads

File.open('myfile.txt', 'r').threach(3, :each_line) {|line| process_line(line)}

您还应该查看peachparallel以了解与多个线程并行工作的其他示例。

除了已经指出的问题之外 - 你的循环不是线程安全的 - 没有任何问题,因为你调用的代码(add_to_file)不是线程安全的。你在线程中不断打开和关闭同一个文件,这会给你带来麻烦。我似乎无法理解你想要做什么,但你需要记住,你绝对不知道不同线程中的事物将要运行的顺序。