C# 一个任务是否应该在另一个任务中运行?

C# 一个任务是否应该在另一个任务中运行?,c#,async-await,task-parallel-library,C#,Async Await,Task Parallel Library,在一个任务中,我有一大堆工作要做(CPU绑定或IO绑定,没有异步接口可供使用)。我想知道这样做是否可以完成任务中的所有非异步工作: async Task DoSomeStuff() { await SomethingAsync(); … DoCpuBoundWork(); … await SomethingElseAsync(); } 或者我应该使用Task。像这样运行吗 async Task DoSomeStuff() { await Some

在一个任务中,我有一大堆工作要做(CPU绑定或IO绑定,没有异步接口可供使用)。我想知道这样做是否可以完成任务中的所有非异步工作:

async Task DoSomeStuff()
{
    await SomethingAsync();
    …
    DoCpuBoundWork();
    …
    await SomethingElseAsync();
}
或者我应该使用Task。像这样运行吗

async Task DoSomeStuff()
{
    await SomethingAsync();
    …
    await Task.Run(() => DoCpuBoundWork());
    …
    await SomethingElseAsync();
}
我知道任务不一定是在另一个线程上执行的,所以我想知道调度程序是否会假设任务是非阻塞的,这会使CPU受限的任务在任务之外工作。运行时请放慢应用程序的速度。例如,如果调度程序决定将CPU绑定的工作调度到应用程序的UI线程,则可能会出现速度减慢


我肯定这个问题以前有人问过,但是我找不到合适的关键字来搜索它,所以很抱歉。

答案是:视情况而定

您指出了调度程序,这正是问题所在。如果您在线程池(默认调度程序)上运行,那么运行CPU绑定的同步工作就完全可以了。如果您在UI线程上运行,这可能会导致糟糕的用户体验

也就是说,虽然这是一个问题,但这不是你的问题。您的契约是,您将在当前调度程序上运行一些工作。由调用者来确定这是否是一个问题,在这种情况下,添加一个
任务。运行
以抵消对另一个调度程序的调用

简而言之,不要使用
wait Task.Run(()=>DoCpuBoundWork())。让知道执行上下文的调用方为您做出决定。

如(深入了解CPU绑定操作的任务和任务一节)中所述,任务在调用它们的线程上运行,CPU绑定的工作实际上应该包装在一个
任务中。运行
,这样它将在另一个(后台)线程上运行。所以,是的,使用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;
}
公共异步任务计算结果(InputData)
{
//这将使线程池上的工作排队。
var expensiveResultTask=Task.Run(()=>DoExpensiveCalculation(data));
//注意,此时,您可以同时执行其他一些工作,
//因为CalculateResult()仍在执行!
//CalculateResult的执行在此产生!
var结果=等待费用结果任务;
返回结果;
}
CalculateResult()在调用它的线程上执行。当调用Task.Run时,它将昂贵的CPU绑定操作DoExpensiveCalculation()排入线程池队列,并接收任务句柄。DoExpensiveCalculation()最终在下一个可用线程上并发运行,可能在另一个CPU内核上。当另一个线程上的DoExpensiveCalculation()正忙时,可以执行并发工作,因为调用CalculateResult()的线程仍在执行

一旦遇到wait,CalculateResult()的执行将交给它的调用方,允许在DoExpensiveCalculation()生成结果时对当前线程执行其他工作。一旦完成,结果将排队在主线程上运行。最终,主线程将返回执行CalculateResult(),此时它将得到DoExpensiveCalculation()的结果


打电话的人应该怎么做很清楚。我提供了一个可等待的异步方法,他们应该等待我的方法。调用方不会执行
await Task.Run(async()=>await dosometuff())@Arshia001为什么不?如果调用方有理由相信该方法将运行一些昂贵的计算,并且不希望在主线程上发生这种情况,那么这就是
Task.run
。而
wait Task.Run(dosomething)
就足够了,不需要在lambdab中等待,因为这是异步方法通常要做的,您等待它们,不再考虑它。