C#中Random类生成随机序列为何频繁出现重复结果?
问题根因
代码存在两处核心错误,直接导致重复序列问题:
- 短时间内重复创建
Random实例:.NET 旧版本Random的默认构造函数以系统时钟Tick作为随机种子,系统时钟的更新分辨率约为10~16ms,在快速循环中连续调用GenerateRandomList时,多次创建Random的时间间隔远小于时钟分辨率,会拿到完全相同的种子。种子一致的Random实例生成的随机数序列完全固定,自然会输出重复的打乱结果。你额外使用new Random().Next(1,10000)作为自定义种子的写法没有解决问题,本质还是在短时间内创建了多个默认种子的Random实例,生成的种子值本身大概率重复。 - 随机索引生成存在边界错误:
Random.Next(minValue, maxValue)的返回值范围是[minValue, maxValue),即包含最小值、不包含最大值。你写的random.Next(0, arr.Count-1)永远无法取到当前列表的最后一个元素,打乱逻辑存在统计偏差。
同时当前实现每次从列表中移除元素的操作会触发列表内部元素移位,时间复杂度为O(n²),处理大列表时性能较差。
修复方案
- 将
Random实例提升为类级别的静态只读字段,全局复用同一个实例,避免短时间重复创建导致种子重复。如果是.NET 6及以上版本,可以直接使用框架内置的线程安全静态实例Random.Shared,无需自行声明。 - 采用时间复杂度为O(n)的标准Fisher-Yates洗牌算法实现打乱逻辑,修正随机索引的边界错误。
修复后的完整代码如下:
class Program { // 单线程场景下全局复用Random实例即可 private static readonly Random _random = new Random(); public static void Main() { for (int j = 0; j < 5; j++) { foreach (var item in GenerateRandomList(new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 })) Console.Write(item + " "); Console.WriteLine(); } } public static List<int> GenerateRandomList(List<int> arr) { // 复制原列表,避免修改传入的原始集合 var tempList = new List<int>(arr); // Fisher-Yates 原地洗牌 for (int i = tempList.Count - 1; i > 0; i--) { // 上界传i+1,保证可以取到0~i范围内的所有索引 int randomIndex = _random.Next(0, i + 1); (tempList[i], tempList[randomIndex]) = (tempList[randomIndex], tempList[i]); } return tempList; } }
补充说明
- 如果是多线程场景使用,.NET Framework旧版本需要对静态
Random实例的调用加锁,避免出现索引越界等问题;.NET Core 3.0+及.NET 5+的Random实例静态共享已经做了线程安全处理,也可以直接用Random.Shared简化代码。 - 不要在高频调用路径中重复
new Random(),这是C#开发中随机数重复问题最常见的诱因。
内容的提问来源于stack exchange,提问作者Priyadarshi Sadiku
相关产品推荐
相关产品推荐

