创建随机16位字符串的更好方法是什么?我已经使用过这段代码了,您能建议一种更有效或更优雅的方式吗?
static string Random16DigitString() {
var rand = new Random();
return $"{rand.Next(100000000).ToString().PadLeft(8, '0')}{rand.Next(100000000).ToString().PadLeft(8, '0')}";
}
PS:我这样做的原因是创建一个0.0000000000000000
形式的字符串,所以我会按照以下方式使用它:
var myString = "0." + Random16DigitString();
答案 0 :(得分:1)
你的解决方案依赖于字符串操作,这会降低它的速度。
尝试:
private static Random r = new Random();
static string Random16DigitString() {
var v = new char[16];
for (var j = 0; j < 16; j++) v[j] = (char)(r.NextDouble()*10 + 48);
return new string(v);
}
这将更快,因为它不依赖于串联操作,如串联或插值。它只是将随机字符戳入char数组,然后将该数组转换为字符串。在我的机器上执行您的解决方案1亿次大约需要47秒,而我的代码大约需要27秒才能产生相同的结果。
r.Next(10) + 48
可以在上面的代码中工作,但它实际上有点慢。 r.Next(48,57)
甚至更慢。
您的代码也可以更简单。 $"{rand.Next(100000000):D8}{rand.Next(100000000):D8}"
会做同样的事情。这几乎是执行的时间。
答案 1 :(得分:-1)
以下是我最终使用的代码:
static readonly Random rnd = new Random();
static string Q() {
// https://stackoverflow.com/questions/767999/random-number-generator-only-generating-one-random-number/768001#768001
// It was decided to use a lock instead of [ThreadStatic] because this api object is designed to be used by many threads simultaneously.
lock (rnd) {
// Get a string representing a positive number greater than 0 and less than 1 with exactly 16 decimal places.
// Original implementation
//return $"0.{rnd.Next(100000000).ToString().PadLeft(8, '0')}{rnd.Next(100000000).ToString().PadLeft(8, '0')}";
// This works but is slow
//return rnd.NextDouble().ToString("F16");
// Found a better faster way: https://stackoverflow.com/questions/48455624/generate-random-16-digit-string/48457354#48457354
var chars = new char[18];
chars[0] = '0';
chars[1] = '.';
for (var i = 2; i < 18; i++)
chars[i] = (char)(rnd.NextDouble() * 10 + 48);
return new string(chars);
}
}
以下是我使用的测试(感谢Jim Berg的回答)
using System;
using System.Diagnostics;
using System.Text;
namespace NetCoreApp1 {
class Program {
static void Main(string[] args) {
var sync = new object();
var rnd = new Random();
Time("method1", () => {
var value = $"{rnd.Next(100000000).ToString().PadLeft(8, '0')}{rnd.Next(100000000).ToString().PadLeft(8, '0')}";
});
Time("method2", () => {
var value = $"{rnd.Next(100000000):D8}{rnd.Next(100000000):D8}";
});
Time("next double", () => {
var value = rnd.NextDouble().ToString("F16"); // turns out surprisingly slow, even slower than the first two
});
Time("method3", () => {
var v = new char[16];
for (var j = 0; j < 16; j++)
v[j] = (char)(rnd.NextDouble() * 10 + 48); // fastest
var value = new string(v);
});
Time("method3 with lock", () => {
lock (sync) {
var v = new char[16];
for (var j = 0; j < 16; j++)
v[j] = (char)(rnd.NextDouble() * 10 + 48); // a tiny bit slower with the lock
var value = new string(v);
}
});
Time("method4", () => {
var sb = new StringBuilder(16);
for (var j = 0; j < 16; j++)
sb.Append((char)(rnd.NextDouble() * 10 + 48)); // slower than method 3
var value = sb.ToString();
});
Console.WriteLine("Press Enter to exit.");
Console.ReadLine();
}
static void Time(string testName, Action action) {
var sw = Stopwatch.StartNew();
for (var i = 0; i < 10000000; i++)
action();
sw.Stop();
Console.WriteLine($"{testName}: {sw.ElapsedMilliseconds}ms");
}
}
}