# 背景
ChatGPT 插件在用户电脑上持续运行一段时间之后,回复率会激增至每条消息都回。
本来会随机回复,但是偶发这个奇怪的现象。我在排查代码许久没有找到原因,于是只能将随机数打印出来观察。今天用户告诉我问题又复现了,于是我观察日志惊讶的发现,随机数结果都是 0!那怪不得回复率那么高
# 原因
我挂了断点上去,发现结果确实是 0,于是我又用即时窗口尝试调用 Next 与 NextDouble,发现结果依然是 0。
于是网上找原因,发现相关内容很少,在 Stack Overflow 十年前的一个问题中提到,多线程访问 Random 对象会导致这一问题,于是我又前往微软官方文档寻找是否有相关描述,很可惜我并没有找到任何与线程安全相关的提示。
# 尝试解决
对于.NetCore2 + 版本来说,解决方案很简单,使用 Random.Shared 即可。
对于低版本.net 来说,解决方案可以分为加锁与其他实现。其中加锁会影响性能,所以此处提供使用 RNGCryptoServiceProvider 的解决方案
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| private static RNGCryptoServiceProvider Rng { get; set; } = new();
public static int Next(int minValue, int maxValue) { if (minValue >= maxValue) { throw new ArgumentOutOfRangeException(); }
long diff = (long)maxValue - minValue; byte[] uint32Buffer = new byte[4]; uint rand; do { Rng.GetBytes(uint32Buffer); rand = BitConverter.ToUInt32(uint32Buffer, 0); } while (rand >= (uint.MaxValue - (((uint.MaxValue % diff) + 1) % diff)));
return (int)(minValue + (rand % diff)); }
public static double NextDouble() { byte[] bytes = new byte[8]; Rng.GetBytes(bytes); ulong ul = BitConverter.ToUInt64(bytes, 0) >> 11; return ul / (double)(1UL << 53); }
public static double NextDouble(double minValue, double maxValue) { if (minValue >= maxValue) { throw new ArgumentOutOfRangeException(); }
return minValue + (maxValue - minValue) * NextDouble(); }
|