在Task中,我有很多工作要做(CPU约束或IO约束,没有异步接口可使用)。我想知道是否可以在这样的任务中完成所有非异步工作:
async Task DoSomeStuff()
{
await SomethingAsync();
…
DoCpuBoundWork();
…
await SomethingElseAsync();
}
还是应该使用Task.Run这样?
async Task DoSomeStuff()
{
await SomethingAsync();
…
await Task.Run(() => DoCpuBoundWork());
…
await SomethingElseAsync();
}
我知道任务不一定要在另一个线程上执行,所以我想知道调度程序是否可能假设任务是非阻塞的,这将使Task之外的CPU绑定工作运行。 。例如,如果调度程序决定将CPU绑定的工作调度到应用程序的UI线程,则可能会降低速度。
我可以肯定已经问过这个问题了,但是我找不到合适的关键词来搜索,对此感到抱歉。
答案 0 :(得分:1)
如this page中所述(对于CPU绑定操作,深入研究Task和Task Task.Run
中,以便它将在另一个(后台)线程上运行。因此,是的,在异步方法中使用Task.Run进行CPU绑定或阻塞工作是正常的,这是正常的。从页面引用:
public async Task<int> CalculateResult(InputData data)
{
// This queues up the work on the threadpool.
var expensiveResultTask = Task.Run(() => DoExpensiveCalculation(data));
// Note that at this point, you can do some other work concurrently,
// as CalculateResult() is still executing!
// Execution of CalculateResult is yielded here!
var result = await expensiveResultTask;
return result;
}
CalculateResult()在调用它的线程上执行。当它调用Task.Run时,它将在线程池上排队昂贵的CPU绑定操作DoExpensiveCalculation(),并接收一个Task句柄。 DoExpensiveCalculation()最终在下一个可用线程(可能在另一个CPU内核)上同时运行。在另一个线程上DoExpensiveCalculation()繁忙时,可以执行并发工作,因为调用CalculateResult()的线程仍在执行。
一旦遇到等待,就会将CalculateResult()的执行交给其调用方,从而允许在DoExpensiveCalculation()产生结果时使用当前线程完成其他工作。完成后,结果将排队等待在主线程上运行。最终,主线程将返回执行CalculateResult(),这时它将获得DoExpensiveCalculation()的结果。
答案 1 :(得分:0)
答案是:这取决于。
您指出了调度程序,这就是问题所在。如果您正在线程池(默认调度程序)上运行,那么运行同步的CPU绑定工作就可以了。如果您正在UI线程上运行,则可能会导致不良的用户体验。
也就是说,虽然这是一个问题,但这不是您的问题。通过实施DoSomeStuff
,您的合同是您将在当前调度程序上运行一些工作。由调用者确定这是否可能是一个问题,在这种情况下,请添加Task.Run
以将调用偏移到另一个调度程序。
简而言之,不要使用await Task.Run(() => DoCpuBoundWork());
。让知道执行上下文的调用者为您决定。