当异步方法在线程上使用时间时,这意味着什么?

时间:2014-05-15 05:48:34

标签: c# asynchronous async-await

来自MSDN

  

async和await关键字不会导致其他线程   创建。异步方法不需要多线程,因为异步   方法不会在自己的线程上运行。该方法在当前运行   同步上下文并仅在线程上使用时间   方法有效。

我从“async和await关键字不会导致创建额外的线程”中得到的结果是它只是使用已经从线程池创建的线程,这很好,但我理解的是“使用时间”在方法处于活动状态时的线程上。“

这是否意味着当我等待任务时,任务“移动”到当前线程还是将结果编组回当前线程?如果查看输出,结果将返回到不同的线程ID,但在完成后在原始线程上完成。我想我错过了这两次行动的“介于两者之间”。

void Main()
{   
    var tasks = new List<Task<byte[]>>();

    Console.WriteLine ("Starting on Managed Thread ID {0}, Background {1}, Pool {2}\n", 
            Thread.CurrentThread.ManagedThreadId,
            System.Threading.Thread.CurrentThread.IsBackground,
            System.Threading.Thread.CurrentThread.IsThreadPoolThread);

    for (int i = 0; i < 5; i++)
    {
        tasks.Add(WriteFile(@"D:\Temp\" + i + ".txt", new String('*', i)));
    }

    Console.WriteLine ("Before Wait()ing on Managed Thread ID {0}, Background {1}, Pool {2}", 
            Thread.CurrentThread.ManagedThreadId,
            System.Threading.Thread.CurrentThread.IsBackground,
            System.Threading.Thread.CurrentThread.IsThreadPoolThread);

    Task.WhenAll(tasks).Wait();

    Console.WriteLine ("Completed on Managed Thread ID {0}, Background {1}, Pool {2}", 
            Thread.CurrentThread.ManagedThreadId,
            System.Threading.Thread.CurrentThread.IsBackground,
            System.Threading.Thread.CurrentThread.IsThreadPoolThread);
}

async Task<byte[]> WriteFile(string path, string text)
{
    FileStream fs = new FileStream(path, FileMode.Create);

    try
    {   
        Console.WriteLine ("Writing to file " + path + " . Managed Thread ID {0}, Background {1}, Pool {2}", 
            Thread.CurrentThread.ManagedThreadId,
            System.Threading.Thread.CurrentThread.IsBackground,
            System.Threading.Thread.CurrentThread.IsThreadPoolThread);

        var bytes = Encoding.Unicode.GetBytes(text);

        await fs.WriteAsync(bytes, 0, bytes.Length);

        Console.WriteLine ("Finished writing to file " + path  + ". Managed Thread ID {0}, Background {1}, Pool {2}", 
            Thread.CurrentThread.ManagedThreadId,
            System.Threading.Thread.CurrentThread.IsBackground,
            System.Threading.Thread.CurrentThread.IsThreadPoolThread);

        return new byte[0];
    }
    finally
    {
        Console.WriteLine ("Finally! " + path + ". Managed Thread ID {0}, Background {1}, Pool {2}\n", 
            Thread.CurrentThread.ManagedThreadId,
            System.Threading.Thread.CurrentThread.IsBackground,
            System.Threading.Thread.CurrentThread.IsThreadPoolThread);

        fs.Dispose();
    }
}

输出:

Starting on Managed Thread ID 46, Background True, Pool False

Writing to file D:\Temp\0.txt . Managed Thread ID 46, Background True, Pool False
Finished writing to file D:\Temp\0.txt. Managed Thread ID 12, Background True, Pool True
Finally! D:\Temp\0.txt. Managed Thread ID 12, Background True, Pool True

Writing to file D:\Temp\1.txt . Managed Thread ID 46, Background True, Pool False
Finished writing to file D:\Temp\1.txt. Managed Thread ID 12, Background True, Pool True
Finally! D:\Temp\1.txt. Managed Thread ID 12, Background True, Pool True

Writing to file D:\Temp\2.txt . Managed Thread ID 46, Background True, Pool False
Finished writing to file D:\Temp\2.txt. Managed Thread ID 12, Background True, Pool True
Finally! D:\Temp\2.txt. Managed Thread ID 12, Background True, Pool True

Writing to file D:\Temp\3.txt . Managed Thread ID 46, Background True, Pool False
Finished writing to file D:\Temp\3.txt. Managed Thread ID 24, Background True, Pool True
Finally! D:\Temp\3.txt. Managed Thread ID 24, Background True, Pool True

Writing to file D:\Temp\4.txt . Managed Thread ID 46, Background True, Pool False
Before Wait()ing on Managed Thread ID 46, Background True, Pool False
Finished writing to file D:\Temp\4.txt. Managed Thread ID 18, Background True, Pool True
Finally! D:\Temp\4.txt. Managed Thread ID 18, Background True, Pool True

Completed on Managed Thread ID 46, Background True, Pool False

1 个答案:

答案 0 :(得分:7)

  

我从&#34;异步和等待关键字中获取的内容不会导致创建其他线程&#34;它只是使用已经从线程池

创建的线程

不,那根本不是真的。 asyncawait根本不在语言级别使用线程池。完全可以使用async / await编写程序,该程序仅使用初始&#34; main&#34;线程。

这并不意味着所有发生在一个线程上 - 它只是异步/等待不要强制额外要创建的线程。编译器本身不会生成任何代码来执行此操作。这完全取决于你正在等待什么。例如,您可以使用Task.Run对任务进行任务,这将(通常)使用线程池,您可以等待它。或者你可以等待调用Task.Delay的结果,await本身并不启动任何线程,只是安排将来完成任务。或者您可以使用异步IO,它可能使用IO完成端口但实际上还没有涉及另一个运行的线程,大部分时间该任务都是活动的&#34;。< / p>

精心设计的等待(如果您使用内置的任何内容,这将包括您)将在与您在同一环境中的相同上下文中安排延续({{1}}之后的所有代码)你开始等待它,除非你特别告诉它不要。那&#34;上下文&#34;可能意味着你回到同一个线程(例如在UI中)但可能没有(例如在线程池上下文中,延续运行的线程池线程并不重要。)

在我看来,值得深入了解异步真正做什么。围绕这个有很多资源,免费和付费墙背后都有: