简体   繁体   English

C#Random不像随机一样工作

[英]C# Random does not work like a random

I have a graph, each node have 4 child nodes. 我有一个图,每个节点有4个子节点。 I wrote a algorithm to generate a random path from a begin node to an end node. 我写了一个算法来生成从开始节点到结束节点的随机路径。 At each node, it chooses a random next node. 在每个节点,它选择一个随机的下一个节点。 Visited node can be revisited. 可以重新访问访问节点。

the code is like the following: 代码如下:

public List<Node> GetPath(Node begin, Node end)
{
    var nodes = new List<Node>();
    var node = begin;
    while (node != end)
    {
        nodes.Add(node);
        var next = node.Children[new Random().Next(4)];
        node = next;
    }

    nodes.Add(end);

    return nodes;
}

But sometimes, the Random does not work as expected. 但有时候,Random不能按预期工作。 The "new Random().Next(4)" keeps generating 0. So it is always the first child node get chose and a very long repeat sequence like node1->node2->node1->node2... is generated and eventually an out of memory exception happens. “new Random()。Next(4)”继续生成0.所以它始终是第一个选择的子节点,并且生成一个非常长的重复序列,如node1-> node2-> node1-> node2 ....发生内存不足异常。

Is there a way to make the Random class works correctly? 有没有办法让Random类正常工作?

The reason is because Random is initialized based on the current time (there is no true random in computers... only psuedo-random). 原因是因为Random是根据当前时间初始化的(计算机中没有真正的随机...只有伪随机)。 The while loop iterates too quickly, and the system time has not registered a change. while循环迭代太快,系统时间没有记录变化。 So you're re-initializing a new Random object that starts with the same value. 所以你要重新初始化一个以相同值开头的新Random对象。

Try creating one Random object that is reused throughout the method: 尝试创建一个在整个方法中重用的Random对象:

public List<Node> GetPath(Node begin, Node end)
{
    var nodes = new List<Node>();
    var node = begin;

    Random r = new Random();
    while (node != end)
    {
        nodes.Add(node);
        var next = node.Children[r.Next(4)];
        node = next;
    }

    nodes.Add(end);

    return nodes;
}

Initialize Random instance outside loop, eg: 初始化外部循环的随机实例,例如:

public List<Node> GetPath(Node begin, Node end)
{
    var nodes = new List<Node>();
    var node = begin;

    var random = new Random();

    while (node != end)
    {
        nodes.Add(node);
        var next = node.Children[random.Next(4)];
        node = next;
    }

    nodes.Add(end);

    return nodes;
}

You mention that the method is being called upon in multiple threads. 您提到在多个线程中调用该方法。 A solution is to have one random number generartor per thread that is seeded by a static rng. 一种解决方案是每个线程有一个随机数generartor,由静态rng播种。

I've also removed the constant 4 and changed it to node.Children.Count . 我还删除了常量4并将其更改为node.Children.Count

static Random seed = new Random();
[ThreadLocal] static Random rng;

public List<Node> GetPath(Node begin, Node end)
{
var nodes = new List<Node>();
var node = begin;

if (rng == null)
   rng = new Random(seed.Next());

while (node != end)
{
    nodes.Add(node);
    var next = node.Children[rng.Next(node.Children.Count)];
    node = next;
}

nodes.Add(end);

return nodes;
}

There are a few things working against you here. 这里有一些对你不利的事情。 The first is that you're expecting a different number every time you ask for one, but that's not what this class does nor is it the definition of random. 第一个是你每次要求一个时都期望一个不同的数字,但这不是这个类所做的,也不是随机的定义。 So, this class is in fact working correctly. 所以,这个类实际上正常工作。

Definition of Random 随机的定义

  1. Made, done, happening, or chosen without method or conscious decision: "a random sample of 100 households". 没有方法或有意识决定的制作,完成,发生或选择:“100个家庭的随机样本”。
  2. Governed by or involving equal chances for each item. 由每个项目管理或涉及平等机会。

Now, this class does its best at giving each option an equal opportunity at being chosen. 现在,本课程尽力为每个选项提供平等的选择机会。 So, when you think of random make sure you're putting into context the definition of the term. 因此,当您想到随机时,请确保您将该术语的定义置于上下文中。 However, remember that this class does not work like the human mind. 但是,请记住,这个类并不像人的头脑工作。

Now, to address the fact that you're getting zero very frequently, it's happening for two reasons. 现在,为了解决你经常得到零的事实,这有两个原因。 First, you are creating a new Random class in every iteration. 首先,您将在每次迭代中创建一个new Random类。 But more importantly, your range is too small because you're expecting it to give you a different number every time on a range of only 4 options, and since it's pseudo-random just as MSDN states you're getting the same answer frequently. 但更重要的是,你的范围太小,因为你期望它每次只在4个选项范围内给你一个不同的数字,并且因为它是伪随机的,就像MSDN声明你经常得到相同的答案一样。

I realize the reason you're only giving it 4 options, but I think you might need to reconsider the type of functionality you're looking for because it would probably lead to less frustration. 我意识到你只给它4个选项的原因,但我认为你可能需要重新考虑你正在寻找的功能类型,因为它可能会减少挫折感。

Here's a really interesting article about Random numbers in C# and question exactly like yours on Stackoverflow :) 这是一篇关于C#中随机数的非常有趣的文章,问题与Stackoverflow上的问题完全一样:)

http://csharpindepth.com/Articles/Chapter12/Random.aspx http://csharpindepth.com/Articles/Chapter12/Random.aspx

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM