背景工作者和垃圾收集?
我可以在方法中定义一个背景工作吗?背景工作者和垃圾收集?
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之前收集工人对象()被执行?
既然你实际上并没有使用太多的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的条件,因此它可能会使此类的实例无法收集垃圾。
这不是OP的问题的答案。不过还是很好的建议。 – JDB
@ Cyborgx37添加了OP的问题的直接答案。 –
让这样的变量超出范围真的是个好主意吗?接下来的程序员会期望看到一个范围内的变量被引用,而不是某个僵尸变量在某处出现。 –
我建议使用委托(Action(Of String)会做),然后调用BeginInvoke。在代码中我看不到BackgroundWorker的任何需求。您仍然可以在方法完成时附加一个事件。 – JDB
更好的方法是使用'QueueUserWorkItem'将其添加到线程池队列中:http://msdn.microsoft.com/en-us/library/system.threading.threadpool.queueuserworkitem.aspx –
@J ...线程池很好,但它确实使得在正确的SynchronizationContext *上处理回调*变得更加困难。不过,TPL可以很好地处理。 –