Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 我无法理解wait/async究竟是如何工作的_C#_.net_Async Await - Fatal编程技术网

C# 我无法理解wait/async究竟是如何工作的

C# 我无法理解wait/async究竟是如何工作的,c#,.net,async-await,C#,.net,Async Await,我开始研究Task,async/await的概念是c#,我在理解它时遇到了很大的问题,至少我不知道如何实现它。我开始重写以前编写的一个旧的测试程序,但现在我想使用这些新概念,而不是线程。基本布局如下: 我有一个简单的类,可以下载网页的HTML内容。 我在另一个类中处理它,在这个类中,我基本上只是将页面解析为我的模型。稍后,我想将其显示到我的UI中。 问题是我的程序没有响应,它在我处理信息时阻塞了用户界面 我是在两天前开始学习的,我在网上读了很多东西,包括MSDN和一些博客,但我还是无法理解。也许

我开始研究Task,async/await的概念是c#,我在理解它时遇到了很大的问题,至少我不知道如何实现它。我开始重写以前编写的一个旧的测试程序,但现在我想使用这些新概念,而不是线程。基本布局如下:

我有一个简单的类,可以下载网页的HTML内容。 我在另一个类中处理它,在这个类中,我基本上只是将页面解析为我的模型。稍后,我想将其显示到我的UI中。 问题是我的程序没有响应,它在我处理信息时阻塞了用户界面

我是在两天前开始学习的,我在网上读了很多东西,包括MSDN和一些博客,但我还是无法理解。也许有人也可以提供一个外观

HtmlDOwnloadCOde:

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(); //当文本阅读器等待信息可用时 //你可以做其他事情 处理某物()

有一些规则需要遵循:

  • 异步函数应返回
    Task
    而不是void,并返回
    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);
    ...