C# 我无法理解wait/async究竟是如何工作的
我开始研究Task,async/await的概念是c#,我在理解它时遇到了很大的问题,至少我不知道如何实现它。我开始重写以前编写的一个旧的测试程序,但现在我想使用这些新概念,而不是线程。基本布局如下: 我有一个简单的类,可以下载网页的HTML内容。 我在另一个类中处理它,在这个类中,我基本上只是将页面解析为我的模型。稍后,我想将其显示到我的UI中。 问题是我的程序没有响应,它在我处理信息时阻塞了用户界面 我是在两天前开始学习的,我在网上读了很多东西,包括MSDN和一些博客,但我还是无法理解。也许有人也可以提供一个外观 HtmlDOwnloadCOde:C# 我无法理解wait/async究竟是如何工作的,c#,.net,async-await,C#,.net,Async Await,我开始研究Task,async/await的概念是c#,我在理解它时遇到了很大的问题,至少我不知道如何实现它。我开始重写以前编写的一个旧的测试程序,但现在我想使用这些新概念,而不是线程。基本布局如下: 我有一个简单的类,可以下载网页的HTML内容。 我在另一个类中处理它,在这个类中,我基本上只是将页面解析为我的模型。稍后,我想将其显示到我的UI中。 问题是我的程序没有响应,它在我处理信息时阻塞了用户界面 我是在两天前开始学习的,我在网上读了很多东西,包括MSDN和一些博客,但我还是无法理解。也许
public async Task<string> GetMangaDescriptionPage(string detailUrl)
{
WebClient client = new WebClient();
Stream data = await client.OpenReadTaskAsync(detailUrl);
StreamReader reader = new StreamReader(data);
string s = reader.ReadToEnd();
data.Dispose();
reader.Dispose();
data.Close();
reader.Close();
return s;
}
很抱歉,这很琐碎,但我自己无法理解。在进行异步时,您需要尝试一直进行异步,避免将阻塞调用与异步调用混合使用 您在事件处理程序中使用的是
async void
,没有wait
尽量避免async void
,除非它是事件处理程序test12
应更新为返回Task
,并在事件处理程序中等待mainBtn\u单击
private async void mainBtn_Click(object sender, RoutedEventArgs e) {
if (mangaList.SelectedItem != null) {
await test12((SingleManagFox)mangaList.SelectedItem);
}
}
private async Task test12(SingleManagFox selectedManga) {
selectedManga = (SingleManagFox)mangaList.SelectedItem;
MangaDetails mangaDetails = new MangaDetails(selectedManga);
MangaDetailsModel mdm = await mangaDetails.ParseMangaDescriptionPage();
txtMangaArtist.Text = mdm.artisName;
txtMangaAuthor.Text = mdm.authorName;
chapterList.ItemsSource = mdm.chapters;
}
也可以考虑更新Web调用以使用<代码> HTTPcli客< /代码>。
class ParseOneManga {
public async Task<string> GetMangaDescriptionPageAsync(string detailUrl) {
using (var client = new HttpClient()) {
string s = await client.GetStringAsync(detailUrl);
return s;
}
}
}
类ParseOneManga{
公共异步任务GetMangaDeDescriptionPageAsync(字符串详细URL){
使用(var client=new HttpClient()){
string s=await client.GetStringAsync(detailUrl);
返回s;
}
}
}
参考资料:-很多人认为async await意味着多个线程同时处理您的代码。情况并非如此,除非您显式启动另一个线程 一个很好的隐喻帮助我解释了async await,它是在中使用的restauran隐喻。在中间搜索某处,等待。< /P> Eric Lipperts将异步等待处理与必须等待水沸腾的厨师进行了比较。他没有等待,而是环顾四周看是否可以做其他事情。完成另一件事后,他回来看看水是否沸腾,并开始处理沸腾的水 你的过程也是如此。一次只有一个线程正忙。这个线程一直在处理,直到他不得不等待一些东西。这通常是一个相当长的过程,在不使用CPU核心的情况下进行处理,例如将文件写入磁盘、加载网页或从外部数据库查询信息 你的线程一次只能做一件事。因此,当它忙于计算时,如果无法对操作员输入做出反应,您的UI就会冻结,直到计算完成。Async await只有在线程有很多次等待其他进程完成时才有帮助 如果您调用一个异步函数,您肯定该函数中的某个地方有一个wait。事实上,如果您将函数声明为async,并且忘记在其中等待,编译器将警告您 当您的调用遇到函数中的wait时,您的线程将进入其调用堆栈以查看是否可以执行其他操作。如果您没有等待,您可以继续处理,直到您必须等待。线程再次向上移动其调用堆栈,查看是否有一个调用方没有等待等 异步任务ReadDataAsync() { //做些准备 使用(文本阅读器文本阅读器=…) { var myReadTask=textReader.ReadToEndAsync(); //当文本阅读器等待信息可用时 //你可以做其他事情 处理某物() 有一些规则需要遵循:
- 异步函数应返回
而不是void,并返回Task
而不是Task
TResult
- 有一个例外:异步事件处理程序返回void而不是
Task
- 在异步函数内部,您应该以某种方式等待。如果您不等待,那么将函数声明为异步是没有用的
的结果无效,wait Task
的结果为wait Task
TResult
- 如果调用异步函数,请查看是否可以执行一些处理,而不是等待调用结果
async Task DoSomethingAsync()
{
var task1 = ReadAsync(...);
// no await, so next statement processes as soon as ReadAsync starts awaiting
DoSomeThingElse();
var task2 = QueryAsync(...);
// again no await
// now I need results from bothtask1, or from task2:
await Task.WhenAll(new Task[] {task1, task2});
var result1 = Task1.Result;
var result2 = Task2.Result;
Process(result1, result2);
...
通常,所有异步功能都由相同的上下文执行。实际上,这意味着您可以像编写单线程程序一样编写程序。这使程序的外观更容易
另一篇帮助我理解async await的文章是
string s=reader.ReadToEnd();
->string s=await reader.ReadToEndAsync()
一个初始观察。尝试避免async void
,除非它是一个事件处理程序。test12
应该更新以返回Task
,并在事件处理程序中等待mainBtn\u单击
。异步时,您需要尝试一直异步。避免阻塞callls@PetSerAl谢谢,这就解决了问题。我猜ui线程被卡住了,再次感谢你的帮助,但我猜核心问题是读者阻止它的地方。感谢提示,现在它在这两种情况下都能工作,但标准是即使发生事件也返回任务(我点击按钮,所以我认为我的函数可以使其无效)?。另一个“offtopic”问题如果您有时间,我在两天前开始使用task/async,但我感觉我的进度非常慢,我明白了
class ParseOneManga {
public async Task<string> GetMangaDescriptionPageAsync(string detailUrl) {
using (var client = new HttpClient()) {
string s = await client.GetStringAsync(detailUrl);
return s;
}
}
}
// after a while you really need the results from the read data,
// so you await for it.
string text = await MyReadTask;
// after the await, the results from ReatToEnd are available
Process(text);
...
async Task DoSomethingAsync()
{
var task1 = ReadAsync(...);
// no await, so next statement processes as soon as ReadAsync starts awaiting
DoSomeThingElse();
var task2 = QueryAsync(...);
// again no await
// now I need results from bothtask1, or from task2:
await Task.WhenAll(new Task[] {task1, task2});
var result1 = Task1.Result;
var result2 = Task2.Result;
Process(result1, result2);
...