Async/Await使用Task.Run异步启动新线程吗?

syn*_*cis 35 c# multithreading async-await

我已经阅读了很多文章,但仍然无法理解这一部分.

考虑以下代码:

    private async void button1_Click(object sender, EventArgs e)
    {
        await Dosomething();
    }

    private async Task<string> Dosomething()
    {
        await Task.Run((() => "Do Work"));
        return "I am done";
    }
Run Code Online (Sandbox Code Playgroud)

第一个问题:

当我单击按钮时,它将调用DoSomething并等待通过调用Task.Run(如果我没有记错)从线程池创建线程的任务,并且所有这些都是异步运行的.所以我实现了创建一个完成我的工作但是异步执行的线程?但是考虑到我不需要任何结果,我只是希望在没有得到任何结果的情况下完成工作,是否真的需要使用async/await,如果是这样,怎么样?

第二个问题:

在异步运行线程时,它是如何工作的?它是在主UI上运行但是在单独的线程上运行还是在单独的线程上运行并且在该方法中是异步的?

DVK*_*DVK 20

  1. 创建异步方法的目的是为了以后可以等待它们.有点像"我要把这些水煮沸,完成准备其余的汤料,然后回到锅里等待水煮沸,这样我就可以做晚餐了." 你开始水沸腾,它在你做其他事情的同时异步,但最终你必须停下来等待它.如果您想要的是"即发即忘",则不需要Async和Await.

在C#中执行fire and forget方法的最简单方法是什么?

  1. 启动新任务会将该任务排队,以便在线程池线程上执行.线程在进程的上下文中执行(例如,运行应用程序的可执行文件).如果这是在IIS下运行的Web应用程序,则该线程将在IIS工作进程的上下文中创建.该线程与主执行线程分开执行,因此无论主执行线程在做什么,它都会关闭并执行其操作,同时,您的主执行线程继续执行自己的工作.

  • @DVK`await`不会阻止当前线程.async/await as keywords与并发无关.等待只是检查任务是否完成.如果是,则执行继续.如果不是,则该方法将未完成的任务返回到调用堆栈中的下一个方法.async/await的一个要点是在等待异步操作完成时不必阻塞当前线程. (10认同)
  • @DVK我引用了你的评论,你声称`await`阻塞当前线程,暗示`async` /`await`与线程有任何关系,即`await`甚至生成线程等等.所有这些事实上是错误的. (7认同)

The*_*kis 10

该类型Task<TResult>要求您TResult从任务中返回a .如果你没有任何东西可以返回,你可以使用Task(顺便说一下,它是基类Task<TResult>).

但请记住,任务不是一个线程.任务是要完成的工作,而线程是工作者.随着您的程序运行,作业和工作人员变得可用且不可用.在幕后,图书馆会将您的工作分配给可用的工作人员,因为创建新工作人员是一项代价高昂的操作,因此通常更愿意通过线程池重用现有工作人员.

  • 感谢您的回答。但是在线程池上的工作线程上启动新任务实际上将使用与 UI 线程不同的线程。我真的看不出更多使用 async/await 的理由,而不是如果我想启动一个任务并等待它完成,然后再完成下一句代码。:/ (2认同)

Mat*_*zer 10

1

有一个很大的区别,如果你不这样做awaitTask,或者你await吧:

  • 案例你不这样做await:DoSomething被调用,但在执行下一句DoSomething Task尚未完成.

  • 案例await:DoSomething被调用,下一句被执行一次DoSomething Task已经完成.

因此,需要async/ await将取决于你想要如何调用DoSomething:如果你不这样做 await,就像把它称为火与忘记方式.

2

它是在主UI上运行但是在单独的线程上运行还是在单独的线程上运行并且在该方法中是异步的?

异步代码有时意味着其他线程(请参阅此Q&A 异步与多线程 - 是否存在差异?).也就是说,如果代码是在与UI一个单独的线程中执行的,或者它让它在恢复时继续处理UI线程,这很好,因为UI循环仍然可以在其他任务完成时更新屏幕平行而不冻结UI.

异步方法(即async方法)是一种语法糖,用于告诉编译器await应将语句视为状态机.C#编译器将您的async/ await代码转换为状态机,等待Task结果的代码在等待的代码之后执行.

有趣的问答

您可能想查看其他问答:

OP说......

[...]但这是否意味着"async/await"将触发一个线程,Task.Run也会触发一个线程,或者它们都是同一个线程?

使用async- await并不意味着"我创建一个线程".以优雅的方式实现延续只是一种语法糖.任务可能是也可能不是线程.例如,Task.FromResult(true)创建一个假任务,以便能够实现异步方法而无需创建线程:

public Task<bool> SomeAsync()
{
    // This way, this method either decides if its code is asynchronous or 
    // synchronous, but the caller can await it anyway!
    return Task.FromResult(true);
}
Run Code Online (Sandbox Code Playgroud)

  • async / await永远不会创建新线程-它在从其调用的同一线程上执行延续。调用的awaitable方法是否在新线程async await上执行是否被忽略 (2认同)
  • @MatíasFidemraizer我现在看来不一定取决于当前的背景,我站得更正:) http://stackoverflow.com/questions/21838651/i-thought-await-continued-on-the-same-thread-as-the -caller,但是,它 - 似乎,不收 (2认同)
  • @markmnl 在 ASP.NET WebAPI/MVC Core 中,“await”在另一个线程池线程上恢复的事实是一个很大的优势,尽管 UI 世界提供了简单性(正如您之前指出的),默认情况下,任何具有共享资源的代码都应该是线程安全的,否则它可能在 WPF 中正常工作,但在 ASP.NET WebAPI 中可能会导致彻底的灾难。 (2认同)