.NET 6 新特性 —— Random.Shared
Intro
最近微软发了一篇 .NET 6 性能提升的博客文章,里面提到了很多有趣的东西,其中有一个是 Random.Shared
这是一个只读的静态属性,并且是一个线程安全的对象,这个东西可以帮助我们简化 Random
对象的使用
Before
首先我们需要知道 Random
不是线程安全的,所以我们如果要在多线程下用 Random
的话,通常需要考虑线程安全问题
既然不是线程安全的,那我们用的时候创建一个就好了,每次都 new 一个,但是这样的话一来代码不够简洁,二来可能会创建比较多的 Random
对象,那么不使用的时候每次 new 要怎么做呢?
比较简单的做法就是加一个锁,如下所示:
public static class RandomGen1
{private static Random _inst = new Random();public static int Next(){lock (_inst) return _inst.Next();}
}
但是这样的话会导致获取锁的效率相对来说会比较低,每次还需要去先拿到锁,所以也有别的解法:
public static class RandomGen2
{private static Random _global = new Random();[ThreadStatic]private static Random _local;public static int Next(){Random inst = _local;if (inst == null){int seed;lock (_global) seed = _global.Next();_local = inst = new Random(seed);}return inst.Next();}
}
上面是一个微软推荐的实现,那么为什么要两个 Random
对象呢,Random
对象产生随机数依赖于一个 seed,默认是使用当前时间,如果时间特别接近的话,会发现即使是不同的 Random 对象产生的随机数有可能是一样的
上面的 _global
对象是用于产生随机的 seed,避免使用默认的 seed,_local
是一个被标记为 ThreadStatic
的对象,每一个线程会拥有一个单独的 Random
对象从而避免线程安全问题。
Sample
有了 Random.Shared
之后,我们就不需要上面的封装了
Console.WriteLine(Random.Shared.Next(1, 100));Parallel.For(0, Environment.ProcessorCount, _ =>
{var thread = new Thread(() => {var arr = new int[10];for (var i = 0; i < arr.Length; i++){arr[i] = Random.Shared.Next(1, 100);}Console.WriteLine(arr.Average());});thread.Start();
});
Random.Shared
的实现也是类似于上面的 ThreadStatic
的解法,但是是从 CLR 的底层去实现的,会比上面的实现方式更为高效,实现代码可以参考 Github:https://github.com/dotnet/runtime/blob/v6.0.0-preview.7.21377.19/src/libraries/System.Private.CoreLib/src/System/Random.cs
More
使用新的 Random.Shared
对象之后就移除掉代码中大量的 new Random
或者自己封装的 Random
了,代码更加简洁了~~
References
https://github.com/dotnet/runtime/issues/43887
https://github.com/dotnet/runtime/pull/50297
https://github.com/dotnet/runtime/pull/50297/files#diff-6fa7e54f57878bb019a11332aeeb42c75430a0ac87c78cdfa9ce382137b3d851R51
https://github.com/dotnet/runtime/blob/v6.0.0-preview.7.21377.19/src/libraries/System.Private.CoreLib/src/System/Random.cs
https://devblogs.microsoft.com/pfxteam/getting-random-numbers-in-a-thread-safe-way/
https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-6/