在同步方法中运行没有 Wait() 的 Task.Run() 有啥影响?

Posted

技术标签:

【中文标题】在同步方法中运行没有 Wait() 的 Task.Run() 有啥影响?【英文标题】:What are the implications of running Task.Run() without Wait() in a synchronous method?在同步方法中运行没有 Wait() 的 Task.Run() 有什么影响? 【发布时间】:2021-06-21 18:55:51 【问题描述】:

我有一个旧代码计时器,每 2 秒运行一次很长的数据库更新查询,类似这样

 private void timer_Elapsed(object sender, ElapsedEventArgs e)
    
      MySyncMethod();
    
    
    private void MySyncMethod()
    
      Task.Run(()=>Run a long running DB update query);
    

假设我们不需要数据库更新结果,上面代码中不等待任务完成有什么影响吗?

Task.Run(()=>Update something in DB).Wait();

据我了解,当我们调用 Task.Run() 时,会从线程池中获取一个新的/可用线程,并且该任务在该线程中运行。因为我们从 sync 方法调用 Task.Run(),所以我们不记得当前的同步上下文并在任务完成时恢复它,就像我们在 async 方法中使用 await Task.Run() 所做的那样。因此,我的另一个问题是,当任务完成时,后续命令是在任务线程中执行还是在原始线程中执行,即 MySyncMethod() 线程?例如,如果我的方法如下所示

private void MySyncMethod()

   
      Task.Run(()=>Run a long running DB update query);
     ... Do something after Task is completed
    

是......做某事......在Task的线程中或Task完成后在MySyncMethod()线程中执行?

【问题讨论】:

如果您调用Task.Run(()=>Run a long running DB update query);,您的数据库更新查询将被推送到Task 的队列中,并且当Task 有可用的Thread 并且它不会阻止您当前线。但是当你输入.Wait() 时,它会等到Task 有一个可用线程来完全运行你的查询,它会阻塞你当前的线程。请看:referencesource.microsoft.com/#mscorlib/system/threading/tasks/… 当我们从同步方法调用Task.Run()时,程序控制是否在Task.Run()调用后立即返回到被调用者的线程?任务完成后,程序控制是否留在任务线程中?当我们从同步方法调用 Task.Run() 时,我们没有像 async/await 方法那样的同步上下文恢复机制。这就是我的问题。 如果有人标记它以明确这里使用的是什么 PL(等),那就太好了。这看起来不是技术中立的...... 如果查询的平均完成时间超过 2 秒,您认为会发生什么?你真的想发出比你的数据库服务器可以处理的更多的数据库请求吗? 好问题。我可能会重新编写此代码以制作异步计时器,即在数据库查询完成或超时之前不会执行下一个计时器迭代。购买它需要大量的代码更改。 【参考方案1】:

对不起,MBK,你有很多问题,所以我需要在这里回答:

1、当我们从同步方法调用Task.Run()时,程序控制是否在Task.Run()调用后立即返回到被调用者的线程?

不,这取决于:

如果 Task 的队列中有 10 个线程和 0->9 个查询,那么您调用 Task.Run(()=>query); 您的查询将立即运行 但如果 Task 在它的队列中有 10 个线程和 100 个查询,那么您调用 Task.Run(()=>query); 您的查询将不会立即运行,您的查询必须等待 91 个其他查询完全运行 2、任务完成后,程序控制是否停留在Task线程中?

我不知道你的意思,但如果你只是打电话给Task.Run(...),你无法知道你的查询是否可以在你的主线程上成功运行。

对于我来说,我只会使用Task.Run(...),我总是需要知道查询的结果,所以我会使用 Task.Run(...).Await() 或者如果我不想阻止主线程,我会结合一个回调来处理这样的查询结果:

Task.Run(()=>
 try 
   //Run a long running DB update query
   callback.onQueryRunSuccess();
 
 catch(Exception e) 
      callback.onQueryRunFailed(e);
 
);

【讨论】:

我假设,您的意思是“我将使用 Task.Run(...).Wait()”,而不是“我将使用 Task.Run(...).Await()”

以上是关于在同步方法中运行没有 Wait() 的 Task.Run() 有啥影响?的主要内容,如果未能解决你的问题,请参考以下文章

Task.RunSynchronously 有啥用?

c#_Task用法总结

如何在 .NET 中取消 Task.Wait() 之后正在运行的 OpenAsync()?

为啥不等待 Task.Run() 同步回 UI 线程/原始上下文?

C#多线程和异步——Task和async/await详解

使用Task.Wait而不是等待异步编程