通用扩展方法比非通用扩展方法慢

Generic extension method is slower than non-generic extension method

我为列表编写了一个扩展方法,用于在排序列表中查找给定值(或下一个更大的值)的索引。

public static int LinearSearch(this List<int> list, int startIndex, int value)
{
    for (int i = startIndex; i < list.Count; i++)
        if (list[i].CompareTo(value) >= 0)
            return i;

    return -1;
}

public static int LinearSearch<T>(this List<T> list, int startIndex, T value) where T : IComparable
{
    for (int i = startIndex; i < list.Count; i++)
        if (list[i].CompareTo(value) >= 0)
            return i;

    return -1;
}

如您所见,我曾经写过一次通用的,一次专门针对整数。如果我注释掉特定于 int 的版本,我的代码运行速度大约要慢得多,就好像我证明了两者一样(假设我在 int-lists 上工作)。

如何使通用版本与非通用版本一样快?我不想复制和粘贴我的代码来获得整数和长整数的性能。

该测试对 1,000 个整数的排序列表运行 10,000,000 次随机查询。

LinearSearch took 9823 ms // generic
LinearSearch took 1553 ms // int-specific

性能测量的测试代码

class Program
{
    const int count = 1000;
    const int runs = 10_000_000;
    static List<int> list = new List<int>();
    static List<int> queries = new List<int>();

    static void Main(string[] args)
    {
        MeasureRuntime(CreateTestData);
        MeasureRuntime(LinearSearch);
    }

    private static void LinearSearch()
    {
        foreach (int query in queries)
            list.LinearSearch(query);
    }

    private static void CreateTestData()
    {
        Random random = new Random(0);
        list.Add(0);
        for (int i = 0; i < count; i++) list.Add(list[list.Count - 1] + random.Next(0, 10));
        for (int i = 0; i < runs; i++) queries.Add(random.Next(0, list.Count - 1));
    }

    private static void MeasureRuntime(Action action)
    {
        Stopwatch stopwatch = new Stopwatch();
        stopwatch.Start();
        action();
        stopwatch.Stop();
        Console.WriteLine($"{action.GetMethodInfo().Name} took {stopwatch.ElapsedMilliseconds} ms");
    }
}

问题是我使用了非通用版本 IComparable 而不是 IComparable<T>,这导致了性能下降。现在,使用 IComparable<T> 通用版本的运行速度与特定类型版本一样快。

public static int LinearSearch<T>(this List<T> list, int startIndex, T value) 
    where T : IComparable<T>
{
    for (int i = startIndex; i < list.Count; i++)
        if (list[i].CompareTo(value) >= 0)
            return i;

    return -1;
}