Task.CompleteTask和Task.FromResult

发布时间 2023-05-26 13:54:26作者: euv

问题点

实现接口中的异步方法时,因为返回值类型是Task或Task<T>,所以即使方法的具体实现逻辑极简执行极快(比如直接返回一个常量字符串),我们可能也需要被迫新建一个Task去执行,如下:

public interface IComputer
{
    Task Do();
    Task<string> DoString();
}
public class MyComputer : IComputer
{
    public Task Do()
    {
        //return Task.Run(() => { Console.WriteLine("逻辑很简单执行很快的代码块,新建一个任务或线程得不偿失,反而损伤性能。"); });
        return Task.Run<string>(() => "逻辑很简单执行很快的代码块,新建一个任务或线程得不偿失,反而损伤性能。");
    }

    public async Task<string> DoString()
    {
        //return Task.Run<string>(() => "逻辑很简单执行很快的代码块,新建一个任务或线程得不偿失,反而损伤性能。");
        return await Task.Run<string>(() => "逻辑很简单执行很快的代码块,新建一个任务或线程得不偿失,反而损伤性能。");
    }
}

上述实现的缺点

开一个Task去执行简单的逻辑会新增开销(构造Task实例,Task排队,线程和上下文切换,回调索取结果,Task状态运转维护等),还不如在当前线程和上下文直接运行划算。


优化手段

可以使用Task.CompletedTask和Task.FromResult优化,二者表示一个已经完成的Task实例,不会产生上下文切换,任务队列排队,回调索取结果等,甚至Task实例都是从缓存中直接返回而不需新建。在满足接口返回形式的前提下,又保证了高性能。

public class MyComputer : IComputer
{
    public Task Do()
    {
        // return Task.FromResult("Hello New Boy");
        return Task.CompletedTask;
    }

    public Task<string> DoString()
    {
        return Task.FromResult("Hello New Boy");
    }
}