通用扩展方法比非泛型扩展方法

时间:2017-09-12 15:39:31

标签: c# performance generics extension-methods

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

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");
    }
}

1 个答案:

答案 0 :(得分:4)

问题是我使用了非通用版本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;
}