为什么我的代码在多个线程上运行?

Lor*_*eno 0 .net c# multithreading task

很长一段时间以来,我一直试图理解.NET中的异步等待内容,但是我却难以成功,所以当我使用异步时,总会发生意想不到的事情。

这是我的应用程序:

namespace ConsoleApp3
{
    class Program
    {
        static async Task Main(string[] args)
        {
            Console.WriteLine("Hello World!");

            var work1 = new WorkClass();
            var work2 = new WorkClass();

            while(true)
            {
                work1.DoWork(500);
                work2.DoWork(1500);
            }
        }
    }

    public class WorkClass
    {
        public async Task DoWork(int delayMs)
        {
            var x = 1;

            await Task.Delay(delayMs)

            var y = 2;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这只是我创建的一个示例,用于检查代码将如何执行。有几件事使我感到惊讶。首先,涉及很多线程!如果我在上面设置了一个断点,则var y = 2;可以看到那里的threadId不同,它可以是1、5、6或其他。这是为什么?我认为async / await不会自己使用其他线程,除非我明确命令(使用Task.Run或创建新线程)。至少本文试图说出我的想法。

好的,但是我们可以说出于某种原因还有其他一些线程-即使它们是,我await Task.Delay(msDelay);也没有ConfigureAwait(false)!据我了解,没有此调用,线程不应更改。

我很难很好地理解这个概念,因为我找不到任何可以包含所有信息而不只是几条信息的优质资源。

Jon*_*eet 10

当异步方法等待某件事时(如果尚未完成),它会安排一个继续,然后返回。问题是继续在哪个线程上运行。如果存在同步上下文,则将继续运行安排在该上下文中运行-通常是UI线程,或者可能是特定的线程池。

在你的情况,你正在运行一个控制台应用程序,这意味着有不同步的情况下(SynchronizationContext.Current将返回null)。在这种情况下,继续在线程池线程上运行。并不是专门创建一个新的线程来运行延续-而是线程池将选择延续,而“主”线程将不运行延续。

ConfigureAwait(false) 用于表示您不希望返回到当前的同步上下文进行继续-但由于您的情况下没有同步上下文,因此没有任何区别。

  • @Stefan:那是一个虚拟方法,因此不同的实现可能有所不同。大概是“默认”实现,但是由于“ SynchronzationContext.Current”为空,我不想推测异步基础结构是使用默认同步上下文(又使用线程池)还是直接使用默认同步上下文。我认为这真的没有太大的区别。 (3认同)