首页 > 解决方案 > 为什么我的代码在多个线程上运行?

问题描述

很长一段时间以来,我一直在尝试理解 .NET 中的 async-await 内容,但我很难成功,当我使用 async 时,总会发生一些完全出乎意料的事情。

这是我的应用程序:

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;
        }
    }
}

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

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

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

标签: c#.netmultithreadingtask

解决方案


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

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

ConfigureAwait(false)用于指示您不想返回到当前同步上下文以继续进行 - 但由于在您的情况下无论如何都没有同步上下文,因此没有区别。


推荐阅读