Task.Run() 和 await Task.Run() 有什么区别?

8

下面的程序使用了一般的Task.Run(),以及使用async和await(异步)方式。在两种情况下,都会从线程池中获取一个不同的线程用于新任务。那么,它们有什么区别呢?异步意味着它应该使用主线程并在任务完成之前释放它。但它也使用了另一个线程而不是主线程。

public class Worker2
{
    public bool IsComplete { get; private set; }
    internal void DoWork()
    {
        this.IsComplete = false;
        Console.WriteLine("Doing Work.");
        Task.Run(new Action(LongOperation));
        Console.WriteLine("Work Completed");
        IsComplete = true;
    }

    private void LongOperation()
    {
            Console.WriteLine("long operation thread thread :" + Thread.CurrentThread.ManagedThreadId);//Thread Id = 7. it is different from main thread id.
            Console.WriteLine("Working!");
            Thread.Sleep(3000);
    }
}

//并且是异步的

public class Worker2
{
    public bool IsComplete { get; private set; }
    internal async void DoWork()
    {
        this.IsComplete = false;
        Console.WriteLine("Doing Work.");       
        await LongOperation();
        Console.WriteLine("Work Completed");
        IsComplete = true;
    }

    private Task LongOperation()
    {

        return Task.Run(() =>
            {
                Console.WriteLine("long operation thread thread :" + Thread.CurrentThread.ManagedThreadId);
                Console.WriteLine("Working!");
                Thread.Sleep(3000);
            });
    }
}

1
请花些时间对您的代码进行格式化 - 适当缩进每一行,将其块引用为4个字符,以便所有内容都显示为代码,并删除每个有用行之间的空白行。 - Jon Skeet
请注意,在第一个示例中,您会在实际完成之前打印出“工作完成”。 - Yacoub Massad
我想了解线程池在两种情况下如何使用线程。 - user3783446
是的,我在这两种情况下使用相同的代码,只不过后者是异步的。 - user3783446
两种情况是一样的,唯一的区别在于你是等待结果还是“发射并忘记”。它们都是异步的,都在线程池线程上运行。 - Charles Mager
显示剩余6条评论
2个回答

15
Task.Run()和await Task.Run()有什么区别?
第一个会启动任务并在任务完成之前立即执行工作。
第二个会启动任务并执行不同的工作,直到任务完成,然后才执行任务之后的工作。
我们可以做一个类比。您的第一个程序就像是这样的:
  • 雇人割草
  • 告诉你的配偶草坪已经被割了
  • 去看Netflix
您的第二个程序是这样的:
  • 雇人割草
  • 在草坪被割时观看Netflix
  • 当草坪被割完且电影结束时,告诉配偶草坪已经被割了。
显然这两种工作流程非常不同。它们都是异步的,但只有后者中包含一个异步等待。我们会异步等待,直到草坪确实被割了才告诉配偶草坪已经被割了。

第二个程序更符合你的第一个比喻。第一个程序更像是雇人割草和看Netflix,但你告诉你的配偶它已经完成了,即使那个人还在忙着。 - Batavia
@Batavia:就是我说的。 - Eric Lippert
嗯,我本来以为它们是反过来的。我的错。 - Batavia
1
这是我最近看到的关于“async”和“Task”的最佳类比! - Ariel

6
你误解了异步代码的含义。每当你调用任何一个函数,该函数将实际的代码执行委托给其他实体(如其他专用线程、线程池等)并立即返回时,就会发生异步调用。异步调用是阻塞调用的反义词。
在C#中,有几种编写异步代码的方法,而await/async只是让编写变得更简单。它在语言的功能方面没有任何添加。它只是一种语法糖,通过提供一种编写异步代码的方式,使程序更容易编写,就像我们编写阻塞代码的方式一样。
话虽如此,Task.Run(new Action(LongOperation));和你第二个片段中的LongOperation()都是异步调用。它们之间的区别在于,在第一个示例中,当Task.Run返回时,紧随其后的代码会立即执行(前提是没有发生线程切换)。而在第二个示例中,跟随await的行只有在LongOperation在线程池上完成时才会执行(DoWork遇到await时立即返回)。
我建议你阅读更多关于TPLasync/await的内容。有很多博客文章介绍这些功能,更不用说详细介绍所有这些特性的好书了。

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