2017-01-10 48 views
5

Mam zestaw zadań, które chcę wykonać sekwencyjnie w wątku w tle, z wynikiem każdego zadania przekazywanego do następnego, oraz z łańcuchem, który zawodzi, jeśli jakikolwiek link w łańcuch nie działa.Łańcuch zadań w współbieżnej Ruby

Dla celów argumentacji powiedzmy, że każde zadanie jest obiektem z metodą exec, która zwraca wartość, chociaż równie dobrze mogłyby to być procs lub lambdas.

Co mam teraz jest coś takiego:

promise = array_of_tasks.inject(nil) do |promise, task| 
      if promise 
       promise.then { |prev_result| task.exec(prev_result) } 
      else 
       Concurrent::Promise.new { task.exec } 
      end 
      end 

promise.on_success { |last_result| log.info("Success: #{last_result} ")} 
promise.rescue { |reason| log.error("Failure: #{reason}")} 

Czy jest bardziej zwięzły sposób, aby to zrobić, albo w Promise API lub gdzie indziej w Równoczesne Ruby? Wygląda to na dość podstawową operację, ale nie widzę istniejącej metody, która to robi.

(Uwaga: jeśli nie ma takiej metody, czy istnieje znana nazwa tego wzorca w świecie przyszłości i obietnic? Czyli, jeśli sam piszę tę metodę, czy istnieje pewne oczywiste nazwa dla niego)

Odpowiedz

2

nie jest krótsza, ale struktura ta może ułatwić dodawanie nowych funkcjonalności:

require 'concurrent' 

class Task 
    def exec(x = 0) 
    sleep 0.1 
    p x + 1 
    end 

    alias call exec 

    def to_promise(*params) 
    Concurrent::Promise.new { exec(*params) } 
    end 
end 

module PromiseChains 
    refine Concurrent::Promise do 
    def chained_thens(callables) 
     callables.inject(self) do |promise, callable| 
     promise.then do |prev_result| 
      callable.call(prev_result) 
     end 
     end 
    end 
    end 
end 

może on być stosowany w ten sposób:

using PromiseChains 

array_of_tasks = Array.new(10) { Task.new } 

array_of_tasks << ->(x) { p x * 2 } 
array_of_tasks << proc { |x| p x * 3 } 

first_task, *other_tasks = array_of_tasks 

chain = first_task.to_promise.chained_thens(other_tasks) 

chain.on_success { |last_result| puts "Success: #{last_result} " } 
chain.rescue { |reason| puts "Failure: #{reason}" } 

chain.execute 
sleep(2) 

It outp uts:

1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
20 
60 
Success: 60