这段代码是同步的还是异步的?

4

以下是我尝试学习Task类的代码。从输出中可以看到主线程和任务线程同时运行。但是在异步方法中,我会收到警告消息,提示:

"警告 1:此异步方法缺少'await'运算符并将同步运行。请考虑使用'await'运算符等待非阻塞API调用,或者使用'await Task.Run(...)'在后台线程上执行CPU绑定工作。"

那么下面的代码是同步的吗?

namespace SampleThreadTaskClass
{
    class Program
    {
        static void Main(string[] args)
        {           
            Task task = new Task(ProcessDataAsync);
            task.Start();

            Console.WriteLine("Enter any key");

            string input = Console.ReadLine();
            Console.WriteLine("You entered: " + input);

            Console.ReadLine(); 
        }

        static async void ProcessDataAsync()
        {
            for (int i = 0; i < 20; i++)
            {
                Thread.Sleep(500);
                Console.WriteLine("processing... " + i);
            }
        }
    }
}

我怀疑你误解了 async。它并不意味着“将这个同步方法变成异步方法”。它的意思是“允许我在这个异步方法中使用异步等待”。该方法必须已经是异步的。同样,await也是如此。它不会使其参数异步化;它只是标识了异步工作流程中必须在继续工作流之前完成工作的一个点。 - Eric Lippert
是的,你说得对。我误解了这些概念。我原以为创建一个Task对象并启动该任务后,它会像后台工作线程一样独立运行在另一个线程中。 - Phil
2
@Phil,请抽出一些时间阅读 Task 之旅,第一部分:构造函数 - Stephen Cleary - Erik Philips
2
此外,尝试在控制台应用程序中学习异步编程是一个非常困惑的方式。控制台应用程序不像 GUI 应用程序那样自然地支持异步编程。建议您在 WPF 或 Winforms 应用程序中进行学习。 - Eric Lippert
3个回答

1

ProcessDataAsync方法实际上是同步的。它声称是异步的,但在这方面它是在撒谎。

然后,您将该同步方法提供给Task的构造函数,该构造函数将在线程池线程中执行该同步方法(顺便说一下,您不应该使用线程池线程;如果要在线程池线程中执行同步方法,则应使用Task.Run)。

当然,对于您的情况,您希望在线程池线程中执行此方法。您的异步操作只是等待。没有必要安排一个新的线程池线程,让它无事可做几秒钟

您应该使ProcessDataAsync实际上是异步的,使用Task.Delay创建一个在指定时间间隔内完成的Task,您可以await它,然后您可以简单地调用ProcessDataAsync,当您想要启动异步方法时,它将实际上是异步的


感谢您深入的解释。 - Phil

0
你应该尝试的是,在开始任务之前先编写一些代码,然后以异步方式启动任务。然后像 ProcessDataAsync 这样的另一个异步方法可以在第一个异步方法中使用 await 运算符。这样你就可以了解异步行为。
这会有所帮助。
static async Task ProcessDataAsync()
    {
        for (int i = 0; i < 20; i++)
        {
            await Task.Delay(500);
            Console.WriteLine("processing... " + i);
        }
    }

当你将返回类型更改为async时,你需要将对ProcessDataAsyc的调用更改为以下内容

 var task = Task.Run(ProcessDataAsync);

是的,你的代码是异步的。


这个方法不应该是 async void,调用代码需要进行适配。 - Servy
是的,我同意它应该返回“Task”。我只是因为问题本身就是这样而将其保留为“void”。“void”应该仅在事件处理的情况下使用。 - tRuEsAtM
1
经过跟随您的代码和从Alexander Sverla那里获得的链接,我现在明白了。谢谢。 - Phil
这是关于async和await的最佳文章之一。阅读它以获得更深入的理解。 - tRuEsAtM

-1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接