2015-07-07 15 views
5

Sto eseguendo un programma in cui scarico file di grandi dimensioni, li analizzo e poi scrivo i dati che ho estratto dal file in un altro file.Una "catena di thread" è una soluzione non valida per questa applicazione Java?

I file richiedono molto tempo per il download e l'analisi, ma l'attività di scrittura richiede solo un minuto o più in media. La mia soluzione che ho buttato insieme era di avere tre fixthreadpools di tre thread.

ExecutorService downloadExecutor = Executors.newFixedThreadPool(3); 
ExecutorService parseExecutor = Executors.newFixedThreadPool(3); 
ExecutorService writeExecutor = Executors.newFixedThreadPool(3); 

Un thread nel pool di download scarica il file, quindi invia un nuovo thread per ThreadPool parser, con il nome del file come parametro. Questo viene fatto all'interno del thread stesso. Il thread di download quindi funzionerà scaricando un altro file da un elenco di URL di file.

Una volta che il thread del parser ha terminato l'analisi dei dati che voglio dal file, invia quindi un nuovo thread contenente i dati al threadpool di scrittura, dove viene quindi scritto in un file .csv.

La mia domanda è se c'è una soluzione più elegante a questo. Non ho davvero fatto un threading molto complesso. Dato che ho un sacco di file da scaricare e analizzare, non voglio che nessuno dei thread sia inattivo in qualsiasi momento. L'idea è che, poiché l'analisi di un file può richiedere un po 'di tempo, potrei anche creare thread separati dedicati al download di quei file.

risposta

8

Perché non utilizzare solo un pool di thread. Download, analisi e salvataggio devono attendere comunque l'uno per l'altro, quindi la migliore separazione delle attività consiste nell'utilizzare un thread per file.

+0

Bene, come ho già detto, questi file possono avere diverse dimensioni di GB. L'analisi può richiedere da oltre 30 minuti a un'ora per essere completata. La mia logica è che invece di aspettare che il file venga analizzato prima di scaricare un nuovo file, invece dedicare thread separati che continueranno a scaricare i file e quando sarà finito, invia quel file al threadpool. Ciò provocherà una coda di file in attesa di analisi. Sembra più efficiente per me. – GreenGodot

+0

Fai la cosa più semplice prima @GreenGodot. La tua operazione complessiva è limitata dalla parte più lenta comunque ... vuoi davvero centinaia di file GB in attesa sul disco? – Dennis

+0

Se è utile, elimina il file scaricato utilizzando File.delete() quando ho finito di analizzare il file. non risolve completamente il problema dello spazio, ma ti aiuta? – GreenGodot

2

Questa non è una cattiva pratica in quanto molti sviluppatori fanno lo stesso tipo di codifica. Ma c'è qualcosa che devi tenere a mente.

Numero uno, non ci si può aspettare che le prestazioni aumentino solo perché si hanno più thread. C'è un numero ottimale di thread basato sul numero di CPU.

Numero due, È necessario accertarsi di come vengono gestite le eccezioni.

Numero tre, è necessario assicurarsi di poter arrestare tutti i pool di thread in un evento in cui è necessario interrompere l'applicazione.

2

Quindi il problema ha due aspetti:

  1. Compute legato
  2. IO legato

Lettura e scrittura per il file è collegato IO. Async IO è il migliore per le attività legate all'IO. Java ha AsynchronousFileChannel che consente di leggere e scrivere file senza preoccuparsi dei pool di thread in cui viene eseguita la continuazione tramite i gestori di completamento. Complete Example.

AsynchronousFileChannel ch = AsynchronousFileChannel.open(path); 
    final ByteBuffer buf = ByteBuffer.allocate(1024); 
    ch.read(buf, 0, 0, 
      new CompletionHandler() { 
       public void completed(Integer result, Integer length){   
        .. 
       } 

       public void failed(Throwable exc, Integer length) { 
        .. 
       } 
      } 
    ); 

E fate lo stesso per le scritture, basta scrivere al canale

ch.write(... 

No per l'analisi del file, questo è un compito di calcolo legato, e si dovrebbe ottenere il vostro core della CPU a caldo per questo, puoi assegnare un pool di thread uguale al numero di core che hai.

executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()) 

Ora quello che viene da ricordare è: è necessario testare il codice e testare il codice simultaneo è difficile. Se non puoi provare la sua correttezza, non farlo.

Problemi correlati