如何将其转换为async-await代码并仅使用1个线程?

时间:2017-09-19 13:55:42

标签: c# .net asynchronous async-await

我有一段像

这样的代码
public static void Main()
{
    Console.WriteLine("Press any key to print 'Hello, world!' after 2 seconds");
    while(true)
    {
        Console.ReadKey();
        Task.Run(() => 
        {
            Thread.Sleep(2000);
            Console.WriteLine(string.Format("Hello world! (from thread {0})", Thread.CurrentThread.ManagedThreadId);
        });
    }
}

如果我快速按下键,当然会创建很多线程,并且这些线程除了等待它们被使用的前2秒之外什么都不做。

我想改变行动

await Task.Delay(2000).ConfigureAwait(false);

但我无法弄清楚如何将async - await s&#34链接起来,一直向上"使这项工作。

1 个答案:

答案 0 :(得分:2)

你的要求并不完全清楚(你真的需要使用没有额外的线程吗?正在使用Task.Delay()作为你目标中不可或缺的一部分吗?),也不是具体的你是什么难以搞清楚。

如果您可以接受一些少量的其他线程,那么Task.Delay()将适合您。当然,您需要使用async方法,因此您可以await它。恕我直言,这在命名方法中更准确,而不是匿名:

public static void Main()
{
    Console.WriteLine("Press any key to print 'Hello, world!' after 2 seconds");
    while(true)
    {
        Console.ReadKey();
        KeyPressed();
    }
}

// WARNING: "async void" is discouraged!
private static async void KeyPressed()
{
    await Task.Delay(2000);
    Console.WriteLine(string.Format("Hello world! (from thread {0})", Thread.CurrentThread.ManagedThreadId);
}

注意:

  • void方法使用async通常不是一个好主意。但是在你的例子中,异常是不太可能的,你似乎也不想等待方法的完成,所以无论如何我都用void写了上面的内容。在您的真实场景中,请仔细考虑这是否真的合适。至少,如果发生异常,您应该在try方法中放置catch / async处理程序,以确保观察到异常。
  • 在控制台程序中,不需要使用ConfigureAwait(),因为您没有同步上下文来继续继续继续。线程池中将发生连续。
  • 以上并不是“仅使用1个帖子”。因为(正如我上面提到的),继续发生在线程池中(没有机制让它回到主线程),仍然会有其他线程使用。但是,它应该少于之前使用的数字,因为只有连续需要一个线程。使用计时器线程发生延迟(好吧,那里还有一个线程......但是它与所有计时器共享)。无论你按键的频率如何,这种方法很可能只涉及少数额外的线程。

我认为没有任何方法可以将解决方案简化为一个线程(即一个用户创建的线程......无论如何.NET都会在您的背后创建线程,因此您永远不会真正拥有.NET进程只有一个线程),除非你使用轮询而不是ReadKey()方法进行输入。你可以做什么,但它是一个非常低效的CPU时间使用。恕我直言,async / await方法在简单性和效率之间取得了最佳平衡。