Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/279.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# 异步方法在后台做什么?_C#_Asynchronous_Async Await_Threadpool - Fatal编程技术网

C# 异步方法在后台做什么?

C# 异步方法在后台做什么?,c#,asynchronous,async-await,threadpool,C#,Asynchronous,Async Await,Threadpool,我已经阅读了关于AsyncAwait的各种文章,我正在尝试深入理解await异步。我的问题是,我发现等待一个异步方法并不会创建一个新线程,它只会使UI响应。如果是这样的话,在使用wait-async时就没有时间增益,因为没有使用额外的线程 到目前为止,我只知道Task.Run()创建一个新线程。 对于Task.WhenAll()或Task.WhenAny()也是这样吗 假设我们有以下代码: async Task<int> AccessTheWebAsync()

我已经阅读了关于AsyncAwait的各种文章,我正在尝试深入理解await异步。我的问题是,我发现等待一个异步方法并不会创建一个新线程,它只会使UI响应。如果是这样的话,在使用wait-async时就没有时间增益,因为没有使用额外的线程

到目前为止,我只知道Task.Run()创建一个新线程。 对于Task.WhenAll()或Task.WhenAny()也是这样吗

假设我们有以下代码:

    async Task<int> AccessTheWebAsync()
            {
                using (HttpClient client = new HttpClient())
                {
                    Task<string> getStringTask = client.GetStringAsync("https://docs.microsoft.com");

                    DoIndependentWork();

                    string urlContents = await getStringTask;

                    return urlContents.Length;
                }
            }
async任务访问webasync()
{
使用(HttpClient=new HttpClient())
{
任务getStringTask=client.GetStringAsync(“https://docs.microsoft.com");
做独立的工作();
字符串urlContents=等待getStringTask;
返回urlContents.Length;
}
}
我的期望:

  • 创建getStringTask任务时,另一个线程将复制当前上下文并开始执行GetStringAsync方法

  • 在等待getStringTask时,我们将查看另一个线程是否已完成其任务,如果未完成,则控件将返回AccessTheWebAsync()方法的调用方,直到另一个线程完成恢复控件的任务


  • 所以我真的不明白在等待任务时如何不创建额外的线程。有人能解释一下等待任务时到底发生了什么吗?

    你的基本假设—任务总是在线程上运行—确实是错误的。一个简单的反例是一个完全不运行的基于计时器的任务:它只是订阅计时器,并在计时器触发时将任务状态设置为“已完成”

    更有用、更实用的任务实例是不在任何地方运行的任务—网络请求:它们发送请求,订阅传入的应答,然后停止运行,释放线程以进行另一项工作*

    所以让我们考虑一下你的实际问题。


    到目前为止,我只知道Task.Run()创建一个新线程。对于Task.WhenAll()或Task.WhenAny()也是这样吗

    否,
    Task。whalll
    不会创建任何新线程。它将等待已经存在的任务完成,而不管它们在哪里运行(也不管它们是否在任何线程中运行!)

    task.whalll
    创建的任务未在任何特定线程中运行!它只检测底层任务何时完成,在所有任务都准备好之后,它自己也会完成<代码>任务。whalll不需要任何线程来执行此操作


    创建getStringTask任务时,另一个线程将复制当前上下文并开始执行GetStringAsync方法

    正如我们前面所看到的,调用像
    GetStringAsync
    这样的异步方法不会在任何特定线程上执行。
    GetStringAsync
    的代码设置这些内容,以便在得到答案时,它能够重新获得控制权(可能是在线程池线程上),并将控制权交还给您。准备工作可以在当前线程上完美完成,不会花费太多时间*



    *免责声明:这是一种简化,事实上,网络异步请求执行的操作顺序要复杂得多。

    一篇帮助我理解async await的文章是,他将async await与厨师做早餐进行了比较。在中间搜索某处,等待。< /P> 如果一个厨师不得不做早餐,他只是在烤面包机里放了一些面包,他不会等面包烤好,而是开始环顾四周,看看他是否能做些别的事情,比如煮开水泡茶

    当看到async等待时,也会发生类似的情况。如果您调用一个异步函数,您就知道其中的某个地方有一个wait。事实上,如果您忘记在异步函数中等待,编译器将警告您

    一旦线程看到等待,它就不会无所事事地等待等待任务完成,而是四处查看是否可以做其他事情。它可以进入调用堆栈,查看是否有一个调用方尚未等待,并执行这些语句,直到看到等待为止。再次进入调用堆栈并执行语句,直到看到等待

    无法保证在未等待的异步调用后继续执行语句的线程与原始线程相同。但是,由于该线程具有相同的“上下文”,因此可以将其视为同一线程。不需要临界截面等

    Console.Writeline(Thread.CurrentThread.ManagedThreadId);
    
    // async call to the text reader to read a line; don't await
    var taskReadLine = myTextReader.ReadLineAsync()
    
    // because I did not await, the following will be executed as soon as a thread is free
    Console.Writeline(Thread.CurrentThread.ManagedThreadId);
    ...
    
    // we need the read line; await for it
    string readLine = await taskReadLine;
    Console.Writeline(Thread.CurrentThread.ManagedThreadId);
    ProcessReadLine(readLine);
    
    无法保证执行DoSomething的线程与用于调用ReadLineAsync的线程相同。如果您在一个简单的测试程序中执行代码,很可能会获得多个线程id

    在等待结果之前,代码不应依赖于要执行的异步函数中的任何语句:

    async Task<int> DoIt()
    {
        this.X = 4;
        await DoSomethingElseAsync(this.X);
        return 5;
    }
    async Task CallDoItAsync()
    {
        this.X = 0;
        var taskDoIt = DoIt();
    
        // you didn't await, it is not guaranteed that this.X already changed to 4
        ...
        int i = await taskDoIt();
        // now you can be certain that at some moment 4 had been assigned to this.X 
    
    更改线程池时要非常小心

    有人说async await只在保持UI响应方面有用,但下面的内容表明它还可以提高处理速度

    非异步:

    void CopyFile(FileInfo infile, FileInfo outFile)
    {
         using(var textReader = inFile.OpenText())
         {
            using (var textWriter = outFile.CreateText())
            {
                // Read a line. Wait until line read
                var line = textReader.ReadLine();
                while (line != null)
                {
                    // Write the line. Wait until line written
                    textWrite.WriteLine(line);
    
                    // Read the next line. Wait until line read
                    line = textReader.ReadLine();
                }
            }
        }
    }
    
    你看到了所有的等待。幸运的是,TextReader和TextWriter可以缓冲数据,否则我们真的必须等到数据写入后才能读取下一行

    async Task CopyFileAsync(FileInfo infile, FileInfo outFile)
    {
         using(var textReader = inFile.OpenText())
         {
            using (var textWriter = outFile.CreateText())
            {
                // Read a line. Wait until line read
                var line = await textReader.ReadLineAsync();
                while (line != null)
                {
                    // Write the line. Don't wait until line written
                    var writeTask = textWrite.WriteLineAsync(line);
    
                    // While the line is being written, I'm free to read the next line. 
                    line = textReader.ReadLine();
    
                    // await until the previous line has been written:
                    await writeTask;
                }
            }
        }
    }
    
    在写一行的时候,我们已经试着读下一行了。这可以提高处理速度

    如果是这样的话,在使用wait-async时就没有时间增益,因为没有使用额外的线程

    这是正确的。本身,
    async
    wait
    不直接使用线程。它们的目的是释放调用线程

    到目前为止,我只知道Task.Run()创建一个新线程。对于Task.WhenAll()或Task.WhenAny()也是这样吗

    没有;无论是
    Task.whalll
    还是
    Task.whany
    都不直接使用任何线程

    Whe
    async Task CopyFileAsync(FileInfo infile, FileInfo outFile)
    {
         using(var textReader = inFile.OpenText())
         {
            using (var textWriter = outFile.CreateText())
            {
                // Read a line. Wait until line read
                var line = await textReader.ReadLineAsync();
                while (line != null)
                {
                    // Write the line. Don't wait until line written
                    var writeTask = textWrite.WriteLineAsync(line);
    
                    // While the line is being written, I'm free to read the next line. 
                    line = textReader.ReadLine();
    
                    // await until the previous line has been written:
                    await writeTask;
                }
            }
        }
    }
    
    int foo = await FooAsync();
    
    Task<int> task = FooAsync();
    if (task is not already completed) 
       set continuation of task to go to "resume" on completion
       return;
    resume: // If we get here, task is completed
    int foo = task.Result;