在 图灵社区:随机数(二) 中,我们给出了一个 NrRandom 类,能够产生更好的伪随机序列。那么,它与 .NET Framework 中的 Random 类相比,性能如何呢?让我们写一个测试程序吧:
using System; using System.Diagnostics; namespace Skyiv.Tester { static class NrRandomTester { static readonly Stopwatch timer = new Stopwatch(); static void TestNext1(Random rand, int n) { long sum = 0; timer.Restart(); for (var i = 0; i < n; i++) sum += rand.Next(); timer.Stop(); Console.WriteLine("{0,14} {1,6:F3} {2:N0}", rand.GetType(), timer.Elapsed.TotalSeconds, (double)sum/n); } static void TestNext2(Random rand, int n, int max) { long sum = 0; timer.Restart(); for (var i = 0; i < n; i++) sum += rand.Next(max); timer.Stop(); Console.WriteLine("{0,14} {1,6:F3} {2:N6}", rand.GetType(), timer.Elapsed.TotalSeconds, (double)sum/n); } static void TestNext3(Random rand, int n, int min, int max) { long sum = 0; timer.Restart(); for (var i = 0; i < n; i++) sum += rand.Next(min, max); timer.Stop(); Console.WriteLine("{0,14} {1,6:F3} {2,12:N3}", rand.GetType(), timer.Elapsed.TotalSeconds, (double)sum/n); } static void TestNextDouble(Random rand, int n) { double sum = 0; timer.Restart(); for (var i = 0; i < n; i++) sum += rand.NextDouble(); timer.Stop(); Console.WriteLine("{0,14} {1,6:F3} {2:N10}", rand.GetType(), timer.Elapsed.TotalSeconds, sum/n); } static void TestNextBytes(Random rand, int n, int size) { long sum = 0; var bs = new byte[size]; timer.Restart(); for (var i = 0; i < n; i++) { rand.NextBytes(bs); foreach (var v in bs) sum += v; } timer.Stop(); Console.WriteLine("{0,14} {1,6:F3} {2:N6}", rand.GetType(), timer.Elapsed.TotalSeconds, (double)sum/n/size); } static void Main() { Console.WriteLine("{0} {1}-bit", Environment.OSVersion, Environment.Is64BitOperatingSystem ? 64 : 32); Console.WriteLine("CLR {0}", Environment.Version); var r0 = new Random(); var nr = new NrRandom(); Console.WriteLine(); int n = 1000000000, max = int.MaxValue; Console.WriteLine("Next(): {0,27:N0}", (max-1)/2.0); TestNext1(r0, n); TestNext1(nr, n); Console.WriteLine(); max = 10000; Console.WriteLine("Next(max): {0,23:N6}", (max-1)/2.0); TestNext2(r0, n, max); TestNext2(nr, n, max); Console.WriteLine(); max = int.MaxValue; int min = 1 - max; Console.WriteLine("Next(min,max): {0,19:N3}", (max-1L+min)/2.0); TestNext3(r0, n, min, max); TestNext3(nr, n, min, max); Console.WriteLine(); Console.WriteLine("NextDouble(): {0,20:N10}", 1/2.0); TestNextDouble(r0, n); TestNextDouble(nr, n); Console.WriteLine(); int size = 1000000, m = n / size; Console.WriteLine("NextBytes(buffer): {0,13:N6}", byte.MaxValue/2.0); TestNextBytes(r0, m, size); TestNextBytes(nr, m, size); } } }
在 Arch Linux 64-bit 操作系统中编译和运行:
$ mcs NrRandomTester.cs NrRandom.cs $ mono NrRandomTester.exe Unix 4.6.3.1 64-bit CLR 4.0.30319.42000 Next(): 1,073,741,823 System.Random 14.920 1,073,744,468 Skyiv.NrRandom 16.619 1,073,777,257 Next(max): 4,999.500000 System.Random 19.831 4,999.476177 Skyiv.NrRandom 15.244 4,999.590640 Next(min,max): 0.000 System.Random 41.936 8,672.938 Skyiv.NrRandom 16.405 -13,744.444 NextDouble(): 0.5000000000 System.Random 17.517 0.4999909586 Skyiv.NrRandom 14.077 0.5000026850 NextBytes(buffer): 127.500000 System.Random 15.483 127.498822 Skyiv.NrRandom 6.291 127.503321
输出结果中:
方法名称: 期望的平均值 System.Random 运行时间(秒) 实际的平均值 Skyiv.NrRandom 运行时间(秒) 实际的平均值
其中每种方法都生成 10 9 个随机数来进行测试。可以看出:
C> NrRandomTester.exe Microsoft Windows NT 6.1.7601 Service Pack 1 64-bit CLR 4.0.30319.42000 Next(): 1,073,741,823 System.Random 11.030 1,073,763,381 Skyiv.NrRandom 11.944 1,073,745,494 Next(max): 4,999.500000 System.Random 16.585 4,999.546877 Skyiv.NrRandom 10.319 4,999.411534 Next(min,max): 0.000 System.Random 31.271 37,382.863 Skyiv.NrRandom 11.942 -39,145.860 NextDouble(): 0.5000000000 System.Random 13.122 0.5000071087 Skyiv.NrRandom 9.548 0.4999977242 NextBytes(buffer): 127.500000 System.Random 12.009 127.497139 Skyiv.NrRandom 7.090 127.503601
测试结果与 Linux 64-bit 操作系统一致。
C:> NrRandomTester.exe Microsoft Windows NT 6.1.7601 Service Pack 1 32-bit CLR 4.0.30319.42000 Next(): 1,073,741,823 System.Random 11.455 1,073,751,534 Skyiv.NrRandom 35.625 1,073,754,659 Next(max): 4,999.500000 System.Random 18.431 4,999.490003 Skyiv.NrRandom 33.778 4,999.364559 Next(min,max): 0.000 System.Random 50.525 17,712.270 Skyiv.NrRandom 46.544 -10,609.773 NextDouble(): 0.5000000000 System.Random 14.538 0.4999985216 Skyiv.NrRandom 26.370 0.4999974172 NextBytes(buffer): 127.500000 System.Random 11.726 127.500430 Skyiv.NrRandom 9.558 127.500100
测试结果出乎意料,除了 Next(min,max) 和 NextBytes(buffer) 方法, NrRandom 类的性能略优于 Random 类,其余方法, NrRandom 类的性能均大大差于 Random 类。我想,这是由于 NrRandom 类生成随机数时,使用 long (64-bit 整数)进行运算,而 32-bit 的操作系统的 64-bit 整数运算的性能低下造成的。