代码之家  ›  专栏  ›  技术社区  ›  Mehrdad Afshari

如何在ruby中锁定fork共享的IO

  •  2
  • Mehrdad Afshari  · 技术社区  · 16 年前

    我们如何锁定多个ruby进程共享的IO?

    考虑一下这个脚本:

    #!/usr/bin/ruby -w
    # vim: ts=2 sw=2 et
    if ARGV.length != 2
      $stderr.puts "Usage: test-io-fork.rb num_child num_iteration"
      exit 1
    end
    CHILD = ARGV[0].to_i
    ITERATION = ARGV[1].to_i
    
    def now
      t = Time.now
      "#{t.strftime('%H:%M:%S')}.#{t.usec}"
    end
    
    MAP = %w(nol satu dua tiga empat lima enam tujuh delapan sembilan)
    
    IO.popen('-', 'w') {|pipe|
      unless pipe
        # Logger child
        File.open('test-io-fork.log', 'w') {|log|
          log.puts "#{now} Program start"
          $stdin.each {|line|
            log.puts "#{now} #{line}"
          }
          log.puts "#{now} Program end"
        }
        exit!
      end
      pipe.sync = true
      pipe.puts "Before fork"
      CHILD.times {|c|
        fork {
          pid = Process.pid
          srand
          ITERATION.times {|i|
            n = rand(9)
            sleep(n / 100000.0)
            pipe.puts "##{c}:#{i} #{MAP[n]} => #{n}, #{n} => #{MAP[n]} ##{c}:#{i}"
          }
        }
      }
    
    }
    

    试着这样做:

    ./test-io-fork.rb 200 50
    

    正如预期的那样,test-io-fork.log文件将包含io竞争条件的迹象。

    我想实现的是为自定义GPS协议制作一个TCP服务器,将GPS点保存到数据库中。因为此服务器将处理1000个并发客户端,所以我想将数据库连接限制为只有一个子级,而不是同时打开1000个数据库连接。此服务器将在linux上运行。

    1 回复  |  直到 16 年前
        1
  •  2
  •   pilcrow    16 年前

    在答案被接受后更新可能是不好的,但原始答案有点误导。ruby是否会单独 write(2) 对自动附加换行符的调用取决于输出IO对象的缓冲状态。

    $stdout (当连接到tty时)通常是线路缓冲的,因此 puts() --给定大小合理的字符串——隐式添加换行符是对 写作(2) 然而,情况并非如此 IO.pipe $stderr 正如OP所发现的那样。

    原始答案

    更换你的主管 pipe.puts() 论点是 换行符终止 字符串:

    pipe.puts "##{c} ... #{i}\n"  # <-- note the newline
    

    为什么?你设置 pipe.sync 希望管道写入是原子的、非交错的,因为它们(可能)小于 PIPE_BUF 字节。但没用,因为鲁比的烟斗 puts() 实施 这就是为什么你的写有时会在预期换行的地方交错。

    以下是你剧本分叉后的一段摘录:

    $ strace -s 2048 -fe trace=write ./so-1326067.rb
    ....
    4574  write(4, "#0:12 tiga => 3, 3 => tiga #0:12", 32) = 32
    4574  write(4, "\n", 1)
    ....
    

    但是,添加自己的换行符可以解决这个问题,确保您的整个记录在一个系统调用中传输:

    ....
    5190  write(4, "#194:41 tujuh => 7, 7 => tujuh #194:41\n", 39 <unfinished ...>
    5179  write(4, "#183:38 enam => 6, 6 => enam #183:38\n", 37 <unfinished ...>
    ....
    

    如果由于某种原因无法为您工作,则必须协调进程间互斥体(如 File.flock() ).

    推荐文章