2012-06-18 73 views
14

我可以在方法中定義一個背景工作嗎?背景工作者和垃圾收集?

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); 
} 

問題:如果下載()函數需要很長的時間來下載文件,可以GC踢和RunWorkerCompleted之前收集工人對象()被執行?

+0

我建議使用委託(Action(Of String)會做),然後調用BeginInvoke。在代碼中我看不到BackgroundWorker的任何需求。您仍然可以在方法完成時附加一個事件。 – JDB

+1

更好的方法是使用'QueueUserWorkItem'將其添加到線程池隊列中:http://msdn.microsoft.com/en-us/library/system.threading.threadpool.queueuserworkitem.aspx –

+0

@J ...線程池很好,但它確實使得在正確的SynchronizationContext *上處理回調*變得更加困難。不過,TPL可以很好地處理。 –

回答

12

既然你實際上並沒有使用太多的BackgroundWorker的功能,我會建議使用TPL此相反:

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

話雖這麼說,在worker對象將不會被垃圾在它運行時收集,因爲ThreadPool線程本身會將worker保留爲「used object」。在完成事件處理程序執行之前,垃圾收集器將無法收集它,此時不會有可能達到BackgroundWorker實例的用戶代碼。

此外,由於閉包使用的實例方法(ReportResults)保留「this」的實例可訪問且不符合GC的條件,因此它可能會使此類的實例無法收集垃圾。

+0

這不是OP的問題的答案。不過還是很好的建議。 – JDB

+1

@ Cyborgx37添加了OP的問題的直接答案。 –

+0

讓這樣的變量超出範圍真的是個好主意嗎?接下來的程序員會期望看到一個範圍內的變量被引用,而不是某個殭屍變量在某處出現。 –