How to wait for Thread notification instead of joining all the Threads?

依然范特西╮ 提交于 2020-01-25 13:14:49

问题


In few words, a user makes a request to my web service, and I have to forward the request to X different APIs. I should do it on parallel, so I'm creating threads for this, and the first Thread that answers with a valid response, I should kill the rest of the threads and give back the answer to my customer right away.

One common pattern in Ruby, is to create multiple threads like

threads << Thread.new {}
threads.each { |t| t.join }

The logic I already have is something like:

results = []
threads = []
valid_answer = nil

1.upto(10) do |i|
  threads = Thread.new do
    sleep(rand(60))
    results << i
  end
end

threads.each { |t| t.join }

valid_answer = results.detect { |r| r > 7 }

But on a code like the previous, I'm blocking the process until all of the threads finish. It could be that one thread will answer back in 1 second with a valid answer (so at this point I should kill all the other threads and give back that answer), but instead, I'm joining all the threads and doesn't make too much sense.

Is there a way in ruby to sleep or wait until one thread answer, check if that answer is valid, and then blocking/sleeping again until all of the threads are done or either until one of them gives me back a valid response?


Edit:

It should be done in parallel. When I get a request from the customer, I can forward the request to 5 different companies.

Each company can have a timeout up to 60 seconds (insane but real, healthcare business).

As soon as one of these companies answer, I have to check the response (if its a real response or an error), if its a real response, I should kill all of the other threads and answer the customer right away (no reason to make him to wait for 60 seconds if one of the requests gives me back a timeout). Also, no reason to make it on a loop (like if I do this on a loop, it would be like 5 x 60 seconds in the worst scenario).


回答1:


Perhaps by making the main thread sleep?

def do_stuff
  threads = []
  valid_answer = nil

  1.upto(10) do |i|
    threads << Thread.new do
      sleep(rand(3))
      valid_answer ||= i if i > 7
    end
  end

  sleep 0.1 while valid_answer.nil?
  threads.each { |t| t.kill if t.alive? }
  valid_answer
end

Edit: there is a better approach with wakeup, too:

def do_stuff
  threads = []
  answer = nil

  1.upto(10) do |i|
    threads << Thread.new do
      sleep(rand(3))
      answer ||= i and Thread.main.wakeup if i > 7
    end
  end

  sleep
  threads.each { |t| t.kill if t.alive? }
  answer
end


来源:https://stackoverflow.com/questions/20682634/how-to-wait-for-thread-notification-instead-of-joining-all-the-threads

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!