2013-07-09 15 views
5

Sto scrivendo un programma che carica i dati da quattro file XML in quattro diverse strutture di dati. Ha metodi come questo:Prestazioni di Ruby con più thread rispetto a un thread

def loadFirst(year) 
    File.open("games_#{year}.xml",'r') do |f| 
    doc = REXML::Document.new f 
    ... 
    end 
end 
def loadSecond(year) 
    File.open("teams_#{year}.xml",'r') do |f| 
    doc = REXML::Document.new f 
    ... 
    end 
end 

etc... 

Io inizialmente solo usato un filo e caricato un file dopo l'altro:

def loadData(year) 
    time = Time.now 
    loadFirst(year) 
    loadSecond(year) 
    loadThird(year) 
    loadFourth(year) 
    puts Time.now - time 
end 

Poi ho capito che dovrebbe usare più thread. La mia aspettativa era che il caricamento di ogni file su un thread separato sarebbe molto vicino a quattro volte più veloce di fare tutto in modo sequenziale (Ho un MacBook Pro con un processore i7):

def loadData(year) 
    time = Time.now 
    t1 = Thread.start{loadFirst(year)} 
    t2 = Thread.start{loadSecond(year)} 
    t3 = Thread.start{loadThird(year)} 
    loadFourth(year) 
    t1.join 
    t2.join 
    t3.join 
    puts Time.now - time 
end 

Quello che ho trovato è che la versione che utilizza più thread è in realtà più lenta rispetto agli altri. Come può essere? La differenza è di circa 20 secondi, ognuno dei quali richiede circa 2 o 3 minuti.

Non ci sono risorse condivise tra i thread. Ciascuno apre un file di dati diverso e carica i dati in una struttura dati diversa rispetto agli altri.

+2

Quale versione della lingua e quale VM stai usando? Credo che la maggior parte dei ruby ​​runtime utilizzi ancora thread "verdi" (leggi: non in realtà multithreading, ma emulati invece in un singolo thread) –

+0

Sto solo usando regolarmente Ruby versione 1.9.3 (su Windows). Ho appena fatto qualche ricerca in più e ho realizzato che uno dei file ha molti più dati rispetto agli altri, quindi questo spiega perché le prestazioni non cambiano di un fattore quattro. Ma gli altri tre prendono ancora collettivamente un minuto, quindi mi aspetto di vedere un incremento delle prestazioni nell'area di un minuto usando più thread ... –

+2

ruby ​​classico ha un GIL - non si ottiene il parallelismo di calcolo perché in generale solo un thread viene eseguito alla volta (con eccezioni per IO e altri casi). prova il tuo codice con jruby –

risposta

3

Penso (ma non sono sicuro) il problema è che stai leggendo (usando più thread) i contenuti posizionati sullo stesso disco, quindi tutti i tuoi thread non possono essere eseguiti simultaneamente perché aspettano l'I/O (disco) .

Alcuni giorni fa ho dovuto fare una cosa simile (ma recuperare dati dalla rete) e la differenza tra sequenziale vs thread era enorme.

Una possibile soluzione potrebbe essere caricare tutto il contenuto del file invece di caricarlo come hai fatto nel codice. Nel tuo codice leggi i contenuti riga per riga. Se carichi tutto il contenuto e poi lo elabori, dovresti essere in grado di eseguire molto meglio (perché i thread non dovrebbero attendere l'I/O)

+0

Grazie, questa è una grande idea. –

0

E 'impossibile dare una risposta definitiva sul motivo per cui il problema parallelo è più lento del sequenziale uno senza molte più informazioni, ma una possibilità è:

Con il programma sequenziale, il disco si propone al primo file, legge tutto, cerca il 2 ° file, legge tutto e così via.

Con il programma parallelo, la testina del disco continua a spostarsi avanti e indietro cercando di servire le richieste di I/O da tutti e 4 i thread.

Non so se esiste un modo per misurare il tempo di ricerca del disco nel sistema: in tal caso, è possibile confermare se questa ipotesi è vera.

+2

Un po 'fuori tema: ho usato il parallelismo dei thread su Ruby per elaborare simultaneamente più richieste di rete e ha fatto miracoli sull'efficienza del mio programma. Era su MRI (CRUBY). Quindi non è come se si debba necessariamente passare a JRuby per trarre vantaggio dall'uso di thread per I/O paralleli. –

Problemi correlati