Sửa Tôi cho rằng cách thích hợp buộc chờ đợi để gọi người lao động không đồng bộ là với một Task.Run, như thế này:Async/chờ đợi cho các phương pháp API dài chạy với tiến độ/hủy
await Task.Run(() => builder.Build(dlg.FileName, cts.Token, new Progress(ReportProgress)));
Có một số ánh sáng từ http://blogs.msdn.com/b/pfxteam/archive/2012/04/12/10293335.aspx.
điều này sẽ dễ dàng nhưng tôi mới không đồng bộ/đang chờ đợi với tôi. Tôi đang xây dựng một thư viện lớp để lộ một API với một số hoạt động dài hạn. Trong quá khứ, tôi đã sử dụng một BackgroundWorker để đối phó với báo cáo tiến độ và hủy, như trong đoạn mã này đơn giản:
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);
}
}
và mã khách hàng giống như:
BackgroundWorker worker = new BackgroundWorker
{ WorkerReportsProgress = true,
WorkerSupportsCancellation = true
};
worker.DoWork += new DoWorkEventHandler(_myWorkerClass.DoSomething);
worker.ProgressChanged += WorkerProgressChanged;
worker.RunWorkerCompleted += WorkerCompleted;
worker.RunWorkerAsync(someparam);
Bây giờ tôi muốn tận dụng mẫu async mới. Vì vậy, trước hết ở đây là làm thế nào tôi muốn viết một phương pháp chạy dài đơn giản trong API của tôi; ở đây tôi chỉ đọc một dòng tập tin bằng cách dòng, chỉ để mô phỏng một quá trình thực thế giới mà tôi sẽ phải chuyển đổi một định dạng file với một số xử lý:
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;
}
}
Vì lợi ích của mẫu này, nói điều này là một phương thức của lớp DummyWorker. Bây giờ, đây là mã của tôi client (một ứng dụng thử nghiệm 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...
}
Việc thực hiện cho giao diện IProgress đến từ http://blog.stephencleary.com/2010/06/reporting-progress-from-tasks.html, vì vậy bạn có thể tham khảo URL đó. Dù sao, trong thử nghiệm sử dụng này giao diện người dùng bị chặn hiệu quả và tôi không thấy tiến bộ. Vì vậy, những gì sẽ là hình ảnh đầy đủ cho một kịch bản như vậy, với tham chiếu đến mã tiêu thụ?
Vâng, 'Task.Run()' là cách để thực hiện điều đó. Hoặc có thể 'Task.Factory.StartNew()' với tập hợp tùy chọn 'LongRunning', nếu hành động thực sự là dài. – svick