return 类型的 Task 是否足以使方法 运行 异步?

Is having a return type of Task enough to make a method run asynchronously?

我有一个简单的方法可以执行复杂的字符串操作并 return 得到结果。可以看到,这个方法的return类型是Task<string>。因此,我可以使用 Task.FromResult(result) 到 return 我的字符串的值。

public Task<string> ComplexOperation()
{
    string result = // Do something complex
    return Task.FromResult(result);
}

然后,我可以使用await关键字来调用这个方法。

public static async Task Main(string[] args)
{
    var myResult = await ComplexOperation();
}

因为我正在等待 CompelxOperation(),(等待任务 return 完成)这个方法 运行 会异步吗?

根据您的评论,您需要执行以下操作:

public Task<string> ComplexOperation()
{
    return Task.Run(() =>  /* Do something complex */);
}

你可以这样玩:

public static async Task Main()
{
    Console.WriteLine("Before" );
    var myResultTask = ComplexOperation();
    Console.WriteLine("After task creation");
    var result = await myResultTask;
    Console.WriteLine("After async await");
}

public Task<string> ComplexOperation()
{    
    Console.WriteLine("Creation");
    return Task.Run(() =>
    {
        Console.WriteLine("In before work");
        Thread.Sleep(500); //simulate work;
        Console.WriteLine("In after work");
        return "Done";
    });
}

并将行为与仅 return Task.FromResult 时切换到您的实施进行比较。在这样的测试示例中也没有多大意义,TBH。

正如您将 Main 方法标记为异步以获取异步方法一样,您需要使用 async 关键字将该方法标记为异步,并将结果设为任务。

但在框架中任务用于 2 个相关但不同的概念,并行化和异步编程。

你正在做的是使用并行化。

所以你只是 运行 不同线程上的一些同步代码。

根据你的例子我认为你需要的是使用并行化,它可以加速一些复杂的计算或者通过使用许多线程并行工作来工作。

异步代码背后的概念是在您等待外部资源(例如来自 Web 服务的某些数据)时释放线程,以允许同时完成其他工作。

因此,如果您需要使用本地资源进行复杂的工作,最好使用没有异步逻辑的任务,而不是使用远程资源时,您可以进行异步操作。

从语义上讲,方法 ComplexOperation 是异步的,因为它 return 是一个可等待的类型,为了遵循 the guidelines 它应该被命名为 ComplexOperationAsync.

Asynchronous methods in TAP include the Async suffix after the operation name for methods that return awaitable types, such as Task, Task<TResult>, ValueTask, and ValueTask<TResult>.

但这不是一个行为良好的异步方法。异步方法应立即 return 一个不完整的 Task,允许调用者异步 await 任务而不会被阻塞。来自 docs:

An asynchronous method that is based on TAP can do a small amount of work synchronously, such as validating arguments and initiating the asynchronous operation, before it returns the resulting task. Synchronous work should be kept to the minimum so the asynchronous method can return quickly.

ComplexOperation方法的作用恰恰相反:它强制调用线程执行复杂的操作,最后交还一个完成的任务。出于所有意图和目的,此操作根本不是异步的。它是 100% 同步和 0% 异步,加上一些开销(雪上加霜)。所以不要这样做,如果有某个库可以做到这一点,请不要使用该库。这简直是​​糟糕的做法。


澄清:由于术语异步方法在不同的上下文中可能有不同的含义,我应该澄清一下这个答案的上下文是消费者的角度,将方法的签名视为合同,并根据可见的合同而不是不可见的实现建立期望。在这种情况下,方法 ComplexOperation 是异步的。如果我们换个角度关注实现,ComplexOperation 方法不是异步的。我的声明 «这简直是糟糕的做法» 指的是破坏契约的做法,并为具有异步契约的方法提供同步实现。我并不是在批评 Task.FromResult 方法本身的使用。只有当它遵循 complex/lengthy/latent 操作时,我才批评它,根据该方法的约定,它应该是异步的。

P.S。我感谢@DmytroMukalov 提供(在 chat 中)合同异步和实现异步之间的有用区别。