字符串.性能比较差的地方

本文关键字:比较 性能 性能比 字符串 | 更新日期: 2023-09-27 18:28:00

我有两个方法,它们接受一个字符串并删除任何"无效"字符(包含在哈希集中的字符)。一个方法使用Linq.Where,另一个使用循环w/char数组。

Linq方法所用的时间(208756.9个刻度)几乎是循环(108688.2个刻度)的两倍

Linq:

    string Linq(string field)
    {
        var c = field.Where(p => !hashChar.Contains(p));
        return new string(c.ToArray());
    }

环路:

    string CharArray(string field)
    {
        char[] c = new char[field.Length];
        int count = 0;
        for (int i = 0; i < field.Length; i++)
            if (!hashChar.Contains(field[i]))
            {
                c[count] = field[i];
                count++;
            }
        if (count == 0)
            return field;
        char[] f = new char[count];
        Buffer.BlockCopy(c, 0, f, 0, count * sizeof(char));
        return new string(f);
    }

我的期望是LINQ将击败循环方法,或者至少与之相当。循环方法甚至没有优化。我一定错过了什么。

林克.何在幕后工作,为什么会输给我的方法?

字符串.性能比较差的地方

如果Mono中ToArray的源代码有任何指示,那么您的实现会获胜,因为它执行的分配更少(向下滚动到第2874行查看方法)。

与LINQ的许多方法一样,ToArray方法包含集合和其他枚举的独立代码路径:

TSource[] array;
var collection = source as ICollection<TSource>;
if (collection != null) {
    ...
    return array;
}

在您的情况下,这个分支没有被采用,所以代码继续进行这个循环:

int pos = 0;
array = EmptyOf<TSource>.Instance;
foreach (var element in source) {
    if (pos == array.Length) {
        if (pos == 0)
            array = new TSource [4];
        else
            // If the number of returned character is significant,
            // this method will be called multiple times
            Array.Resize (ref array, pos * 2);
    }
    array[pos++] = element;
}
if (pos != array.Length)
    Array.Resize (ref array, pos);
return array;

正如您所看到的,LINQ的版本可能会多次分配和重新分配阵列。另一方面,您的实现只执行两个分配——最大大小的前一个分配和复制数据的最后一个分配。这就是为什么你的代码更快。