【问题标题】:Can I use LINQ to generate random numbers reliably in C#?我可以使用 LINQ 在 C# 中可靠地生成随机数吗?
【发布时间】:2015-10-15 13:30:30
【问题描述】:

我熟悉 RandomRNGCryptoServiceProvider 以及如何在 C# 中使用它们生成随机数。

但我也知道以下方法:

int start = 10;
int end = 50;
Enumerable.Range(start, end).OrderBy(o => Guid.NewGuid()).Take(5);

鉴于LINQ 的流媒体功能和此方法的给定线程安全性(而不是使用共享Random),我找不到不使用此方法的理由。

除了性能,我还缺少什么?

【问题讨论】:

  • 即使在 Random 的情况下,它也将是线程安全的,因为不是并行 LINQ 查询。所以你可以用同样的方法使用 Random ,这取决于你想要什么随机数据 - 只是字节,或整个 guids
  • Sergey,我指的是更一般的情况,sharing 不同线程之间的随机对象。不过你是对的。
  • startend 有很大差异时,您需要生成和排序大集合
  • @Alexander,这不是真的,LINQ 的性质允许值被流式传输,因此没有排序或生成大集合,话虽如此,生成一个新的Guid对于结果 Enumerable 中的每个值,这可能并不理想。
  • @MaYaN 我不这么认为。如果不了解所有 it 元素,您将无法对集合进行排序。可惜我现在不能给出证明链接。

标签: c# .net linq random


【解决方案1】:

Guid 类旨在创建唯一数字,而不是随机数字。

无法保证您将获得均匀分布。它肯定不符合加密相关任务的安全条件。

只需使用最适合特定任务的类。 Random 用于快速伪随机数据,RNGCryptoServiceProvider 用于安全。

Linq 方法是一种 hack。当您遇到线程问题时,以既定的方式使其成为线程安全的。

【讨论】:

  • @abelenky - 我知道。答案适用于排序值的分布。
  • 除了完全平坦之外的任何东西 - 如果 Guid 是按升序生成的呢?
【解决方案2】:

如果你想使用 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

【讨论】:

  • 我不是在寻找LINQ 接口替换,我很想知道在问题中使用该方法的优缺点。无论如何感谢您的回答。
【解决方案3】:

你的技术的问题(或可能有好处?)是它不会重复范围内的任何数字。

在真正的随机集中,您可以合理地看到有时重复的数字。

示例: {12, 46, 12, 27, 12} 应该是有效的输出。

使用您的方法,您将永远不会看到 12 重复。
如果您希望以随机顺序返回数字 10-50,但每个只返回一次,那么您真的需要 Shuffling Algorithm

【讨论】:

  • 非常好的观察,Enumerable.Repeat 可能会提供一种解决方法/破解方法,但在这种情况下使用它是完全疯狂的!
猜你喜欢
  • 2012-02-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多