2012-06-18 32 views
14

Posso definire un lavoratore in background in un metodo?Background worker e garbage collection?

private void DownLoadFile(string fileLocation){ 
    BackgroundWorker worker = new BackgroundWorker(); 

    worker.DoWork += new DoWorkEventHandler((obj, args) => { 
     // Will be executed by back ground thread asynchronously. 
     args.Result = Download(fileLocation); 
    }); 

    worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler((obj, args) => { 
     // will be executed in the main thread. 
     Result r = args.Result as Result; 
     ReportResult(r); 
    }); 

    worker.RunWorkerAsync(fileLocation); 
} 

Domanda: Se Scarica function() richiede molto tempo per scaricare il file, può GC calci in e ritirare oggetto operaio prima della RunWorkerCompleted() viene eseguito?

+0

Si consiglia di utilizzare un delegato (azione (di stringa) dovrebbe fare) e quindi chiamare BeginInvoke. Non vedo alcun bisogno di BackgroundWorker in questo codice. È ancora possibile allegare un evento per quando il metodo è fatto. – JDB

+1

Un modo migliore per farlo sarebbe quello di aggiungerlo alla coda del pool di thread utilizzando 'QueueUserWorkItem': http://msdn.microsoft.com/en-us/library/system.threading.threadpool.queueuserworkitem.aspx –

+0

@ J ... Il threadpool è bello, ma rende più difficile la gestione della richiamata * a destra SynchronizationContext *. La TPL lo gestisce bene, però. –

risposta

12

Dato che non si sta usando molte delle funzionalità di BackgroundWorker, mi consiglia di utilizzare il TPL per questo, invece:

private void DownLoadFile(string fileLocation) 
{ 
    Task.Factory.StartNew(() => Download(fileLocation)) 
     .ContinueWith(t => ReportResult(t.Result), TaskScheduler.FromCurrentSynchronizationContext()); 
} 

Detto questo, l'oggetto worker non sarà spazzatura raccolti una volta che è in esecuzione, come il thread ThreadPool stesso manterrà lavoratore come un "oggetto usato". Il garbage collector non sarà in grado di raccoglierlo fino a dopo l'esecuzione del gestore di eventi di completamento, in quel momento non ci sarebbe alcun codice utente che potrebbe raggiungere l'istanza di BackgroundWorker.

Inoltre, è probabile che l'istanza di questa classe non venga raccolta dai dati obsoleti, poiché i metodi di istanza (ReportResults) utilizzati dalla chiusura mantengono l'istanza di "questo" accessibile e non idonea per GC.

+0

Questa non è davvero una risposta alla domanda dell'OP. Ancora un buon consiglio però. – JDB

+1

@ Cyborgx37 Aggiunta una risposta diretta alla domanda dell'OP. –

+0

E 'davvero una buona idea lasciare che una variabile del genere esca dall'ambito di applicazione, però? Il programmatore che viene dopo di lui si aspetta di vedere una variabile in-scope referenziata, non una qualche variabile zombie che è là fuori nell'etere da qualche parte. –