我已经在C#中下载了异步/等待的示例代码
https://code.msdn.microsoft.com/Async-Sample-Example-from-9b9f505c
现在我已经尝试对其进行调整以实现另一个目标:我想在执行GetStringAsync
这就是我所做的并且可以正常工作,但是我对自己的代码有些怀疑。是正确的方法还是正确的方法。
1-使用Task.WhenAll
并行运行两个任务
2-是否应使用UpdateUIAsync
完成每200ms在等待文本后附加一个点的任务方法dispatcher.begininvoke
还是这样?
3-再次使用字段finished
来同步行为,再次“确定”还是有更好的方法?
public partial class MainWindow : Window
{
// Mark the event handler with async so you can use await in it.
private async void StartButton_Click(object sender, RoutedEventArgs e)
{
// Call and await separately.
//Task<int> getLengthTask = AccessTheWebAsync();
//// You can do independent work here.
//int contentLength = await getLengthTask;
finished = false;
int[] contentLength = await Task.WhenAll(AccessTheWebAsync(), UpdateUIAsync());
resultsTextBox.Text +=
String.Format("\r\nLength of the downloaded string: {0}.\r\n", contentLength[0]);
}
bool finished = false;
// Three things to note in the signature:
// - The method has an async modifier.
// - The return type is Task or Task<T>. (See "Return Types" section.)
// Here, it is Task<int> because the return statement returns an integer.
// - The method name ends in "Async."
async Task<int> UpdateUIAsync()
{
resultsTextBox.Text = "Working ";
while (!finished)
{
resultsTextBox.Text += ".";
await Task.Delay(200);
}
resultsTextBox.Text += "\r\n";
//Task<int> write = new Task<int>(() =>
//{
// Dispatcher.BeginInvoke((Action)(() =>
// {
// resultsTextBox.Text = "Working ";
// while (!finished)
// {
// resultsTextBox.Text += ".";
// Task.Delay(200);
// }
// resultsTextBox.Text += "\r\n";
// }));
// return 1;
//});
return 1;
}
async Task<int> AccessTheWebAsync()
{
// You need to add a reference to System.Net.Http to declare client.
HttpClient client = new HttpClient();
// GetStringAsync returns a Task<string>. That means that when you await the
// task you'll get a string (urlContents).
Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");
// The await operator suspends AccessTheWebAsync.
// - AccessTheWebAsync can't continue until getStringTask is complete.
// - Meanwhile, control returns to the caller of AccessTheWebAsync.
// - Control resumes here when getStringTask is complete.
// - The await operator then retrieves the string result from getStringTask.
string urlContents = await getStringTask;
finished = true;
// The return statement specifies an integer result.
// Any methods that are awaiting AccessTheWebAsync retrieve the length value.
return urlContents.Length;
}
}
答案 0 :(得分:1)
async-await
报告进度的方式是通过Sven Marnach及其实现IProgress Interface。
如果您将UpdateUIAsync
方法更改为:
private async Task UpdateUIAsync(IProgress<string> progress, CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
progress.Report(".");
await Task.Delay(200);
}
}
然后您可以像这样使用它:
private async void StartButton_Click(object sender, RoutedEventArgs e)
{
this.resultsTextBox.Text = "Working ";
using (var cts = new CancellationTokenSource())
{
var task = AccessTheWebAsync();
await Task.WhenAny(
task,
UpdateUIAsync(
new Progress<string>(s => this.resultsTextBox += s),
cts.Token));
cts.Cancel();
var contentLength = await task;
}
this.resultsTextBox.Text +=
String.Format("\r\nLength of the downloaded string: {0}.\r\n", contentLength);
}
答案 1 :(得分:1)
1-使用Task.WhenAll并行运行两个Task
这些操作正在同时运行,Task.WhenAll
是异步并发的适当机制。您所有的代码仅在一个线程上运行,因此这里没有真正的并行性。
不需要2-是否应该使用dispatcher.begininvoke完成在任务文本中每200ms附加一个点的任务方法UpdateUIAsync还是这样?
Dispatcher
,因为代码在UI线程上运行。但是,我建议您使用IProgress<T>
模式as Paulo recommended,因为这有助于使您的代码更具可测试性,并减少与特定UI的联系。
3-共享使用字段完成来同步行为,再次“确定”还是有更好的方法?
在这种情况下,不受保护的共享字段确实起作用,因为所有代码都在单个线程上运行。但是,我建议使用CancellationToken
模式,以使语义更清晰:AccessTheWebAsync
完成时,您的代码想取消 UpdateUIAsync
。使用这样的既定模式不仅可以阐明意图,还可以使代码更可重用。