2012-06-18 55 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

让这样的变量超出范围真的是个好主意吗?接下来的程序员会期望看到一个范围内的变量被引用,而不是某个僵尸变量在某处出现。 –