Naf*_*tis 6 c# backgroundworker async-await
编辑 我认为强制等待异步调用worker的正确方法是使用Task.Run,如下所示:
await Task.Run(() => builder.Build(dlg.FileName, cts.Token, new Progress(ReportProgress)));
Run Code Online (Sandbox Code Playgroud)
从http://blogs.msdn.com/b/pfxteam/archive/2012/04/12/10293335.aspx获得了一些启示.
这应该很容易,但我是async/await的新手,所以请耐心等待.我正在构建一个类库,通过一些长时间运行的操作公开API.在过去,我使用BackgroundWorker来处理进度报告和取消,就像在这个简化的代码片段中一样:
public void DoSomething(object sender, DoWorkEventArgs e)
{
BackgroundWorker bw = (BackgroundWorker)sender;
// e.Argument is any object as passed by consumer via RunWorkerAsync...
do
{
// ... do something ...
// abort if requested
if (bw.CancellationPending)
{
e.Cancel = true;
break;
} //eif
// notify progress
bw.ReportProgress(nPercent);
}
}
Run Code Online (Sandbox Code Playgroud)
客户端代码如下:
BackgroundWorker worker = new BackgroundWorker
{ WorkerReportsProgress = true,
WorkerSupportsCancellation = true
};
worker.DoWork += new DoWorkEventHandler(_myWorkerClass.DoSomething);
worker.ProgressChanged += WorkerProgressChanged;
worker.RunWorkerCompleted += WorkerCompleted;
worker.RunWorkerAsync(someparam);
Run Code Online (Sandbox Code Playgroud)
现在我想利用新的异步模式.所以,首先我要在API中编写一个简单的长期运行方法; 在这里,我只是逐行阅读一个文件,只是为了模拟一个真实世界的过程,我必须通过一些处理来转换文件格式:
public async Task DoSomething(string sInputFileName, CancellationToken? cancel, IProgress progress)
{
using (StreamReader reader = new StreamReader(sInputFileName))
{
int nLine = 0;
int nTotalLines = CountLines(sInputFileName);
while ((sLine = reader.ReadLine()) != null)
{
nLine++;
// do something here...
if ((cancel.HasValue) && (cancel.Value.IsCancellationRequested)) break;
if (progress != null) progress.Report(nLine * 100 / nTotalLines);
}
return nLine;
}
}
Run Code Online (Sandbox Code Playgroud)
为了这个示例,请说这是DummyWorker类的方法.现在,这是我的客户端代码(WPF测试应用程序):
private void ReportProgress(int n)
{
Dispatcher.BeginInvoke((Action)(() => { _progress.Value = n; }));
}
private async void OnDoSomethingClick(object sender, RoutedEventArgs e)
{
OpenFileDialog dlg = new OpenFileDialog { Filter = "Text Files (*.txt)|*.txt" };
if (dlg.ShowDialog() == false) return;
// show the job progress UI...
CancellationTokenSource cts = new CancellationTokenSource();
DummyWorker worker = new DummyWorker();
await builder.Build(dlg.FileName, cts.Token, new Progress(ReportProgress));
// hide the progress UI...
}
Run Code Online (Sandbox Code Playgroud)
IProgress界面的实现来自http://blog.stephencleary.com/2010/06/reporting-progress-from-tasks.html,因此您可以参考该URL.无论如何,在这个使用测试中,UI被有效阻止,我看不到任何进展.那么,参考消费代码,这种情景的全貌是什么?
正如该博客文章顶部所述,该帖子中的信息已过时.您应该使用IProgress<T>.NET 4.5中提供的新API.
如果您正在使用阻止I/O,那么请阻止您的核心方法:
public void Build(string sInputFileName, CancellationToken cancel, IProgress<int> progress)
{
using (StreamReader reader = new StreamReader(sInputFileName))
{
int nLine = 0;
int nTotalLines = CountLines(sInputFileName);
while ((sLine = reader.ReadLine()) != null)
{
nLine++;
// do something here...
cancel.ThrowIfCancellationRequested();
if (progress != null) progress.Report(nLine * 100 / nTotalLines);
}
return nLine;
}
}
Run Code Online (Sandbox Code Playgroud)
然后在Task.Run调用它时将其包装:
private async void OnDoSomethingClick(object sender, RoutedEventArgs e)
{
OpenFileDialog dlg = new OpenFileDialog { Filter = "Text Files (*.txt)|*.txt" };
if (dlg.ShowDialog() == false) return;
// show the job progress UI...
CancellationTokenSource cts = new CancellationTokenSource();
DummyWorker worker = new DummyWorker();
var progress = new Progress<int>((_, value) => { _progress.Value = value; });
await Task.Run(() => builder.Build(dlg.FileName, cts.Token, progress);
// hide the progress UI...
}
Run Code Online (Sandbox Code Playgroud)
或者,您可以重写Build以使用异步API,然后直接从事件处理程序中调用它而不将其包装Task.Run.
| 归档时间: |
|
| 查看次数: |
5880 次 |
| 最近记录: |