在 .NET 中的 ConvertAll 和 Select 方法哪個效能好

邓磊1024發表於2024-10-12

.NET 的 List 中提供了 ConvertAllSelect 兩個方法,在開發中實際上應該使用哪一個?

接下來透過基準測試指令碼來對比效能。

先編寫基準測試指令碼:

[MemoryDiagnoser]  
public class BenchmarksTerrible  
{  
    private readonly List<Order> _orders;  
  
    public BenchmarksTerrible()  
    {  
        var random = new Random(420);  
        _orders = Enumerable.Range(1, 100000).Select(_ => new Order { Status = random.Next().ToString() })  
            .ToList();;  
    }  
  
    public static OrderBasicInfo ConvertOrder(Order order) => new() { Status = order.Status };  
    
    public List<OrderBasicInfo> GetOrderBasicInfos() => _orders.ConvertAll(new Converter<Order, OrderBasicInfo>(ConvertOrder));
  
  
  
    [Benchmark]  
    public List<OrderBasicInfo> ConvertAll()  
    {  
        return GetOrderBasicInfos();  
    }  
  
    [Benchmark]  
    public void Select()  
    {  
        var _ = _orders.Select(x => new OrderBasicInfo { Status = x.Status });  
    }  
  
    [Benchmark]  
    public List<OrderBasicInfo> SelectToList()  
    {  
        return _orders.Select(x => new OrderBasicInfo { Status = x.Status })  
            .ToList();  
    }  
}

測試結果如下:

Method Mean Error StdDev Gen 0 Gen 1 Gen 2 Allocated
ConvertAll 4,118,657.86 ns 77,004.920 ns 79,078.383 ns 382.8125 375.0000 132.8125 3200166 B
Select 14.70 ns 0.287 ns 0.330 ns 0.0076 - - 72 B
SelectToList 4,115,770.49 ns 68,067.640 ns 63,670.513 ns 382.8125 375.0000 132.8125 3200174 B

然後將程式碼的 GetOrderBasicInfos 方法進行如下調整,重新測試。

public List<OrderBasicInfo> GetOrderBasicInfos() => _orders.ConvertAll(ConvertOrder);  

測試結果如下:

Method Mean Error StdDev Gen0 Gen1 Gen2 Allocated
ConvertAll 4,160,022.71 ns 57,100.202 ns 50,617.842 ns 382.8125 375.0000 132.8125 3200166 B
Select 14.49 ns 0.209 ns 0.174 ns 0.0076 - - 72 B
SelectToList 4,118,527.16 ns 58,763.369 ns 49,070.075 ns 382.8125 375.0000 132.8125 3200174 B

經過兩次測試可以發現,Select 方法的效能最好,因為它的執行時間最短,分配的記憶體最少,並且幾乎不需要垃圾回收。ConvertAllSelectToList 方法的執行時間非常接近,SelectToList 稍好一些,但都比 Select 方法慢得多,且分配的記憶體較多,垃圾回收次數也較高。

因此,對於開頭的問題,我的結論是兩個方法的效能差不多,都可以使用。

相關文章