使用线程/加载运行多个Ruby脚本副本只会生成一个正在运行的副本

时间:2016-07-21 16:41:28

标签: ruby multithreading

我正在开发服务器,因此开发了一个用于测试的客户端脚本。如果我启动多个/多个命令处理器并使用“ruby client.rb”在每个命令处理器中启动它,则此客户端脚本运行良好。为了使这个过程更有效,我正在尝试编写一个父脚本“threads.rb”,它可以使用线程激发尽可能多的客户端。它们都启动但只有最后一个在使用threads.rb时有效运行。

client.rb可以访问Redis,我在那里使用互斥锁来防止冲突。我没有锁定客户端的其他部分,也没有做任何事情来防止其中的问题。我希望能够使用threads.rb,因为client.rb可以在多个命令处理器中运行

threads.rb是:

threads = 4
the_threads = []
(1..threads).each do |thread|
  puts "Creating thread #{thread}"
  the_threads << Thread.new(thread) do |t|
    puts "Running Client #{thread};\n"
    load "./samples/client.rb"
  end
end

client.rb

%w(rubygems bundler faye/websocket eventmachine json redis redis-classy redis-mutex).each { |m| require m }
Dir["./lib/*.rb", "./lib/**/*.rb"].each { |file| require file }
class ClientWs

  def self.em_run
    EM.run do
      puts "EM is running."
      uri = 'localhost'
      redis_uri = URI.parse("redis://127.0.0.1:6379")
      redis ||= Redis.new(host: redis_uri.host, port: redis_uri.port, password: redis_uri.password)
      RedisClassy.redis = Redis.new(host: redis_uri.host, port: redis_uri.port, password: redis_uri.password)

      mutex = RedisMutex.new(:device, block: 0.5, sleep: 0.5)
      if mutex.lock
        device = 0
        channel = 100
        type = 'Reader'
        begin
          channel += 1
          type = type == 'Display' ? 'Reader' : 'Display'
          device += 1 if type == 'Display'
          lockbox = "Lbox_#{device}"
          unit = "#{lockbox}.#{type}.Status"
          status = redis.get(unit)
        end until status.nil? || !status
        channel = type == 'Reader' ? "RDR:#{channel}" : "DSP:#{channel}"
        result = redis.set(unit, 'Offline')
        puts "Connecting with:#{unit}; Using channel:#{channel};"
        url = uri == 'localhost' ? "ws://#{uri}:3000/#{channel}" : "ws://#{uri}/#{channel}"
        puts url
        @ws = Faye::WebSocket::Client.new(url)
        start = Time.now
        count ||= 0
        mutex.unlock
      else
        puts 'RedisMutex failed to obtain mutex lock.'
        exit
      end

      timer = EventMachine.add_periodic_timer(5+rand(5)) {
        count += 1
        count.even? ? send({"ECHO": {"CMD": "PING"}}) : send({"CMD": "PING"})
        Thread.pass
      }

      @ws.on :open do |event|
        ClientWs.send({"OPEN": lockbox})
      end

      @ws.on :message do |event|
        @ip_address ||= Addrinfo.ip(URI.parse(event.target.url).host).ip_address
        begin
          parsed = JSON.parse event.data
        rescue => e
          puts ">>>> [Error! Failed to parse JSON]"
          puts ">>>> [#{e.message}]"
          puts ">>>> #{event.data}"
        end
        puts ">> #{@ip_address}:#{channel}:#{event.data};"
        #@ws.close
      end

      @ws.on :close do |event|
        timer.cancel
        stop = Time.now - start
        result = redis.del(unit)
        puts "#{stop} seconds;"
        p [:close, event.code, event.reason]
        ws = nil
        ClientWs.em_run
      end
    end
  end

  def self.send message
    payload = message.is_a?(Hash) ? message : {payload: message}
    @ws.send(payload.to_json)
  end

end
ClientWs.em_run

1 个答案:

答案 0 :(得分:0)

我将它转换为使用Kernel#spawn代替线程。

the_pids = []
(1..pids).each do |pid|
  puts "Running Client #{pid};\n"
  Dir.chdir("D:/projects/wsserver/")
  the_pids << spawn(RbConfig.ruby, "./samples/client.rb")
end