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

时间:2015-06-08 15:10:28

标签: c# multithreading asynchronous async-await

我正在使用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));
            }
        }
    }

1 个答案:

答案 0 :(得分:4)

  

我不是"屈服"回到线程函数

该方法产生一次命中await udpc.ReceiveAsync(),这就是async-await的工作原理。 ListenAsync本身同步阻塞,但由于没有同步上下文发挥作用,延续可以将自己编组到任意线程池线程上。

  

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

不是真的。通常,当您在控制台应用程序内运行时,它使用默认的TaskScheduler,它在内部使用线程池在任意线程池线程上执行延续。一个ReceiveAsync()完成,它的继续需要在某个地方安排,那个地方在线程池上。

在旁注中 - 没有理由在委托上使用async修饰符,因为您不是在等待内部任何内容,而是同步阻止。