c# - 提高 "shuffle"效率

标签 c# extension-methods

现在,我正在使用以下代码创建一个 Shuffle 扩展:

public static class SiteItemExtensions
{
    public static void Shuffle<T>(this IList<T> list)
    {
        var rng = new Random();
        int n = list.Count;
        while (n > 1)
        {
            n--;
            int k = rng.Next(n + 1);
            T value = list[k];
            list[k] = list[n];
            list[n] = value;
        }
    }
}

我正在寻找一种更快、更有效的方法来完成这项工作。现在,使用 Stopwatch 类,洗牌 100,000,000 个项目大约需要 20 秒。有没有人有任何想法可以使它更快?

最佳答案

这突出了现代计算机设计中经常被忽视的一个方面。通过一个愚蠢的改变,它可以快 3 倍以上:

            int k = 0; rng.Next(n + 1);  // silly change

现在在内循环中有更多 语句,但速度更快。您看到的是 CPU 缓存的效果。该算法的缓存局部性非常差,下一个要从数组中读取的元素已经在缓存中的可能性非常低。这需要花费昂贵的费用才能到达较慢的外部缓存和极慢的内存总线。稍后需要的数组元素被加载到缓存中的可能性非常高。但是它们在需要时仍然存在的可能性非常低,您的列表太大而无法容纳缓存。

无法解决此问题,这是算法设计中固有的。然而,使用现实的列表大小是一个显而易见的解决方案。在具有 1000 个元素的列表上运行 100,000 次是快 3 倍。

关于c# - 提高 "shuffle"效率,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7605267/

相关文章:

具有特定类型的 List 上的 C# 扩展方法

c# - 未优化的 IEnumerable<>.Last with predicate

c# - IDictionary<K, IEnumerable/IList/ICollection<V>> 上的单一扩展方法

swift - 命令因信号 : Segmentation fault: 11 while emitting IR SIL function 而失败

c# - 为什么 C# 允许通过接口(interface)扩展方法而不是类进行多重继承?

c# - 如何在拆分字符串时对 List<LabelItem> 进行排序?

c# - System.Text.Json 序列化不适用于抽象成员

c# - C# 中的 Mp3 音频音序器和混音器

c# - 多线程引用?

c# - 我们如何从一种表单更改所有其他表单的背景颜色?