【发布时间】:2019-03-11 09:39:54
【问题描述】:
我已经下载了 C# 中 async/await 的示例代码
https://code.msdn.microsoft.com/Async-Sample-Example-from-9b9f505c
现在我尝试对其进行调整以实现不同的目标:我想在执行GetStringAsync 的同时更新 GUI
所以这就是我所做的并且它有效,但我对我的代码有些怀疑。如果它是正确的或“正确”的方式来做到这一点。
1- 使用Task.WhenAll 并行运行两个Task
2- 任务方法 UpdateUIAsync 每 200 毫秒附加一个点到等待文本是否应该使用 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;
}
}
【问题讨论】:
-
对于第三个问题,请查看 ManualResetEvent Class docs.microsoft.com/en-us/dotnet/api/… 或其他线程同步助手,如 Semaphore、EventWaitHandle 等。
-
@Max - 为什么?此示例中没有多线程...因为所有代码都在 UI 线程上运行。
-
@AlexeiLevenkov,嗯...我不太确定。在引擎盖下,它使用
Task.Run,它(根据其描述)“将指定的工作排队以在线程池上运行......”。我同意,Task.Run方法倾向于重用当前线程,而不是提供真正的多任务处理,但是,如果应用程序已经在使用大量任务/线程等,它可能会改变。 -
@Max “它使用
Task.Run”中的“它”是什么?帖子中的代码和 MSDN 示例中的代码都没有直接使用Task.Run,Task.Delay和HttpClient.GetStringAsync都没有创建线程(同样不使用Task.Run)... -
@Max 很高兴知道......但这不应该(假设 HttpClient 被合理实现)从外部观察 - 帖子中的所有代码都将在同一个线程上运行,而 HttpClient 在另一个线程上执行的任何操作不应访问共享数据。
标签: c# async-await dispatcher