我可以在c#中使用LINQ可靠地生成随机数吗?
本文关键字:随机数 LINQ 我可以 | 更新日期: 2023-09-27 18:17:48
我熟悉Random
和RNGCryptoServiceProvider
,以及如何使用它们在c#中生成随机数。
但我也知道以下方法:
int start = 10;
int end = 50;
Enumerable.Range(start, end).OrderBy(o => Guid.NewGuid()).Take(5);
考虑到LINQ
的流处理能力和此方法的线程安全性(与使用共享Random
相反),我找不到不使用此方法的理由。
除了性能,我还错过了什么?
Guid类旨在创建唯一的数字,而不是随机的数字。
不能保证得到均匀分布。对于加密相关的任务,它肯定不安全。
只使用最适合某项任务的类。Random用于快速伪随机数据,RNGCryptoServiceProvider用于安全性。
Linq方法是一个hack。当您遇到线程问题时,请以既定的方式使其线程安全。
如果你想使用linq接口,我建议这样做:
public IEnumerable<int> GetRandomSequence(int start, int end)
{
var generator = new Random();
while (true)
yield return generator.Next(start, end);
}
和
var randomSequence = GetRandomSequence(10, 50).Take(5);
但是在这种情况下,使用计数器而不是"while (true)"会更安全,以避免无限循环:
var sequence = GetRandomSequence();
var someOtherSequence = sequence.Skip(5); // here we forget to call Take, Zip, TakeWhile etc.
// some code
var someVar = someOtherSequence.ToList(); // endless call here
var someOtherVar = someOtherSequence.Join( ... ) // and here
您的技术的问题(或可能的好处?)是它不会重复范围内的任何数字。
在真正的随机集中,您可以合理地看到一个数字偶尔重复。
示例: {12, 46, 12, 27, 12}
应该是有效的输出。
使用您的方法,您将永远不会看到12
重复。
如果您希望以随机顺序返回数字10-50,但每个数字只返回一次,那么您真的需要一个洗牌算法。