为什么c#中的异步代码在工作线程上运行

本文关键字:工作 线程 运行 代码 异步 为什么 | 更新日期: 2023-09-27 17:54:39

我正在玩c#中的async/await,虽然我认为我理解大多数概念,但我无法解释为什么代码行"var rxres = await…"第一次在我的UDP线程上运行,并且在进一步接收数据包后在工作线程上运行。据我所知,我不是"屈服"回到线程函数,它仍然活着,所以ReceiveAsync的所有调用应该在我创建的线程上运行。

    static void Main(string[] args)
    {
        var ewh = new EventWaitHandle(false, EventResetMode.ManualReset);
        var udpThread = new Thread(async () =>
        {
            ListenUdpAsync().Wait();
        });
        udpThread.Name = "UDP THREAD";
        udpThread.Start();
        ewh.WaitOne();
    }
    static public async Task ListenUdpAsync()
    {
        var localPort = 5555;
        var localBind = new IPEndPoint(IPAddress.Any, localPort);
        using (var udpc = new UdpClient(localBind))
        {
            while(true)
            {
                var rxres = await udpc.ReceiveAsync();
                Console.WriteLine("Rx From: " + rxres.RemoteEndPoint);
                Console.WriteLine("Rx Data: " + Encoding.ASCII.GetString(rxres.Buffer));
            }
        }
    }

为什么c#中的异步代码在工作线程上运行

我不会"屈服"回线程函数

方法在到达await udpc.ReceiveAsync()时产生,这就是async-await的工作方式。ListenAsync本身同步阻塞,但由于没有同步上下文起作用,因此continuation能够将自己封送到任意线程池线程上。

所以ReceiveAsync的所有调用都应该在我创建的线程上运行。

没有。通常,当您在控制台应用程序中运行时,它使用默认的TaskScheduler,它在内部使用线程池在任意线程池线程上执行延续。当ReceiveAsync()完成后,需要在某个地方调度它的延续,这个地方在线程池中。

附带说明-没有理由在委托上使用async修饰符,因为您不等待内部的任何内容,而是同步阻塞。