2009-11-08 15 views
5

Ho un compito che devo eseguire, do_stuff(opts), che richiederà ~ 1 s ciascuno, anche mentre 1 - 10 di questi sono in esecuzione in parallelo. Ho bisogno di raccogliere una serie di risultati per ogni operazione alla fine.Threading in Ruby con un limite

Se ho 30 stoffe da fare, come dovrei utilizzare threading in modo efficace per mettere in coda le do_stuff(opts) operazioni in modo da non più di 10 sono in esecuzione contemporaneamente, ma la serie di risultati non è dato/stampati/etc fino a quando tutti (30) le attività sono state completate?

Di solito ho almeno un codice per cercare di illustrare cosa intendo, ma con il thread sono un po 'in perdita! Grazie in anticipo

risposta

0

Inoltre, date un'occhiata a this esercitazione se siete nuovi a discussioni Ruby.

+1

Il collegamento sembra essere morto. C'è una copia da qualche parte? – Naremy

+0

@Naremy, ho corretto il collegamento. Per favore, invertire quando hai un momento. – jkndrkn

+0

Non ero il downvoter ma se posso renderlo felice;) – Naremy

1

Se si sta davvero dopo le prestazioni, si potrebbe anche voler esaminare jruby.
Utilizza thread effettivi del sistema operativo e non i thread verdi le altre implementazioni di ruby ​​utilizzano

4

Non so quanto funzionerà per un'applicazione più complessa, ma ho trovato qualcosa di simile a funzionare bene per un semplice scenario di threading con MacRuby.

thread_limit = 4 

threads = [] 
things_to_process.each do |thing| 
    until threads.map { |t| t.status }.count("run") < thread_limit do sleep 5 end 
    threads << Thread.new { the_task(thing) } 
end 
output = threads.map { |t| t.value } 

il ciclo until attende intorno fino a quando non sono inferiori al numero specificato di thread creati in esecuzione prima di consentire l'esecuzione del thread principale di proseguire per avviare il thread successivo.

alla variabile di uscita verrà assegnata una matrice dei valori restituiti da the_task con un ordinamento corrispondente all'array di input things_to_process. Il thread principale bloccherà fino a quando ogni thread creato non restituirà un valore.

+1

Ho avuto più fortuna ad usare thread.alive? invece di stato: 'threads.map {| t | t.alive?}. count (vero) ' – theglauber

1

Questa soluzione raccoglie risultati in serie di risultati $. Permette di creare thread "thread_limit", quindi li attende per completarli prima di crearne altri.

$results = [] 

    def do_stuff(opts={}) 
    'done' 
    end 

    def thread_wait(threads) 
    threads.each{|t| t.join} 
    threads.each {|t| $results << t } 
    threads.delete_if {|t| t.status == false} 
    threads.delete_if {|t| t.status.nil? } 
    end 

    opts = {} 
    thread_limit = 20 
    threads = [] 
    records.each do |r| 
    thread_wait(threads) while threads.length >= thread_limit 
    t = Thread.new { do_stuff(opts) } 
    t.abort_on_exception = true 
    threads << t 
    end 
    # Ensure remaining threads complete 
    threads.each{|t| t.join} 
0

Io uso parals e paralsmap:

def parals(objects, n: 50) 
    objects.shuffle.each_slice(n).map do |g| 
    print '{' 
    threads = [] 
    g.map { |i| threads << Thread.new(i) { |i| yield(i) } } 
    threads.each(&:join) 
    print '}' 
    end 
end 

def paralsmap(objects, n: 50) 
    res = [] 

    objects.each_slice(n).map do |g| 
    print '{' 
    threads = [] 
    g.map { |i| threads << Thread.new(i, res) { |i| res << yield(i) } } 
    threads.each(&:join) 
    print '}' 
    end 

    res 
end 

es .:

parals((0..100).to_a) { |i| puts i } 
urls = parals((0..100).to_a) { |i| "https://google.com/?q=#{i}" } 

È possibile utilizzare il parametro n per limitare il numero di thread.