【问题标题】:C# Seeding StaticRandom in parallel.for to get a reproducible sequenceC# Seeding StaticRandom in parallel.for 以获得可重现的序列
【发布时间】:2013-02-18 23:43:27
【问题描述】:

我正在开发一个需要在 parallel.for 循环中使用随机数的 C# 项目。为此,我使用 Jon Skeet 的 MiscUtil 中的 StaticRandom 类。

为了测试,我希望能够重现我的结果。因此,我尝试播种底层 System.Random 以在每次测试运行时获得相同的序列。然而,即使有了种子,我每次都会得到不同的结果。在常规的 for 循环中,每次都输出相同的序列。下面有重现我的问题的代码(您必须使用机器的输出更新预期的序列)。

有没有办法播种 Random 以便我可以在 parallel.for 循环中获得可重现的序列?

    [TestMethod]
    public void MultiThreadedSeededRandom()
    {
        var actual = new ConcurrentBag<int>();
        Parallel.For(0, 10, i =>
        {
            actual.Add(StaticRandom.Next(1000));
        });

        WriteActualToOutput(actual);

        var expected = new int[] { 743, 51, 847, 682, 368, 959, 245, 849, 192, 440, };

        Assert.IsTrue(AreEqual(expected, actual.ToArray()));
    }

    public static bool AreEqual<T>(T[] expected, T[] actual)
    {
        if (expected.Length != actual.Length)
            return false;

        for (int i = 0; i < expected.Length; i++)
        {
            if (!expected[i].Equals(actual[i]))
                return false;
        }
        return true;
    }

    private static void WriteActualToOutput(ConcurrentBag<int> acual)
    {
        var result = string.Empty;
        result += "new int[] {";
        foreach (var value in acual)
        {
            result += value.ToString() + ",";
        }
        result += "};";

        Trace.WriteLine(result);
    }

    public static class StaticRandom
    {
        private static Random random = new Random(1231241);
        private static object myLock = new object();

        public static int Next(int max)
        {
            object obj;
            Monitor.Enter(obj = StaticRandom.myLock);
            int result;
            try
            {
                result = StaticRandom.random.Next(max);
            }
            finally
            {
                Monitor.Exit(obj);
            }
            return result;
        }
    }

【问题讨论】:

  • 如果您在应用程序启动时获取所有随机样本并存储它们以供以后使用会怎样。那么采样线程使用它们的顺序就无关紧要了。
  • 另外,也许在取消调用的特定线程中进行所有采样?

标签: c# multithreading random seed


【解决方案1】:

当您使用Parallel.For 时,按照设计,您将得到不按顺序排列的结果,因为每次迭代将以非确定性的方式并行运行。如果您需要相同的“随机”数字序列,则需要以可靠的顺序调用Random.Next()。这不适用于多个线程。

与其尝试使用Parallel.For填充随机数,不如考虑提前生成“随机”数序列,然后使用Parallel.For根据这些数进行处理。这样,您将始终以正确的顺序生成数字,从而保留顺序。

【讨论】:

  • 啊,是的。我以为它们是完全不同的序列,但实际上只是顺序不同。我会尝试在实际的parallel.For之前生成随机数。谢谢!
【解决方案2】:

另外,如果您从未使用过 StringBuilder,您可以在输出方法中使用它的效率:

private static void WriteToArrayString(ICollection items)
    {
        var result = new StringBuilder("new []{");

        var index = 0;
        foreach(var value in items)
        {
            if (index == (items.Count - 1))
            {
                result.Append(string.Concat(value));
                index++;
                continue;
            }
            result.Append(string.Concat(value, ','));
            index++;
        }
        result.Append("};");

        Trace.WriteLine(result.ToString());
    }

【讨论】:

    猜你喜欢
    • 2020-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多