我正在开展一个项目,我需要生成8个随机数.我有一个问题,随机数部分由于某种原因非常耗时.我的意思是8个随机数,我需要一个长度为8个字符的字符串,由数字0-9组成.例01234567或23716253等
我尝试循环8次,使用Random.Next(0,9)生成一个随机数,然后将它们转换为字符串并将它们连接到最终字符串.我还尝试使用Random.Next(0,99999999)生成一个随机数,只是将数字转换为字符串并用0填充为8.
看起来两者都很慢,我需要想出一个更快的方法.我不介意打电话给其他语言或某些东西,如果它有助于提高性能.
这里有一些额外的信息要添加.我不认为我会找到任何超级高效的东西.我必须生成这个数字大约50000次.当我用47000进行测试时,花了8:39秒.这只是每次.011秒,但它只是减慢了因为即时通讯也在使用有表.我也称为hashtable.ContainsKey()全部47000次,总共花了58秒.这是一个很大的区别.
这是我最初使用的代码.Convert.ToString(rg.Next(0,99999999)).PadLeft(8,'0');
这里有一些代码可以解决这个问题.以下是我收到的包含价值的时间:00:00:00.4287102包含密钥:00:01:12.2539062生成密钥:00:08:24.2832039添加:00:00:00
TimeSpan containsValue = new TimeSpan();
TimeSpan containsKey = new TimeSpan();
TimeSpan generateCode = new TimeSpan();
TimeSpan addCode = new TimeSpan();
StreamReader sr = new StreamReader(txtDictionaryFile.Text);
string curWord = sr.ReadLine().ToUpper();
int i = 1;
DateTime start;
DateTime end;
while (!sr.EndOfStream)
{
start = DateTime.Now;
bool exists = mCodeBook.ContainsValue(curWord);
end = DateTime.Now;
containsValue += end - start;
if (!exists)
{
string newCode;
bool kExists;
do
{
start = DateTime.Now;
Random rnd = new Random();
StringBuilder builder = new StringBuilder(8);
byte[] b = new byte[8];
rnd.NextBytes(b);
for (int i = 0; i < 8; i++)
{
builder.Append((char)((b[i] % 10) + 48));
}
newCode = builder.ToString();
end = DateTime.Now;
generateCode += end - start;
start = DateTime.Now;
kExists = mCodeBook.ContainsKey(newCode);
end = DateTime.Now;
containsKey += end - start;
}
while (kExists);
start = DateTime.Now;
mCodeBook.Add(newCode, curWord);
end = DateTime.Now;
addCode += start - end;
}
i++;
curWord = sr.ReadLine().ToUpper();
}
Run Code Online (Sandbox Code Playgroud)
您看到的实际问题不太可能是随机数生成缓慢,而是您经常执行它.随着"代码簿"中项目数量的增加,现有数字发生冲突的可能性也会增加.这将导致你的do ... while循环一直反复执行直到找到可用的东西.
我不知道你在代码簿中加载了多少数据,但是如果它完全没有,你需要考虑重复条目会发生什么.
在你的情况下,问题变得非常糟糕,因为你在循环中调用"new Random()".这导致随机数发生器被"重新接种",其值从当前时间(实际上是自系统启动以来的总毫秒数)得出.这意味着每当你遇到碰撞时,循环将立即重新执行,并将选择与之前完全相同的随机种子值,这将导致您生成的"随机"数字也与先前尝试的相匹配数.实际上,根据机器的速度,它可能会反复重复生成相同的数字.
适合当前代码结构的此问题的最快解决方法是简单地删除您调用"new Random"的所有位置,并在您重用的方法的开头使用单个随机数生成器.这将确保每次进行循环时不会重置它并降低重复生成相同数字的可能性.
要真正解决这个问题,你将不得不更多地考虑你正在使用的随机数.您生成的数字是随机的还是只需要是唯一的非常重要.此外,您可以生成更大的随机数,以降低任何重复的概率.一个足够大的随机数将消除重复的机会.最极端的是使用Guid.NewGuid().ToString()来生成密钥
另外,作为旁注.您显示的性能数字可能无法准确测量正在发生的情况.DateTime.Now没有足够的"分辨率"来测量像你使用它一样小而快的东西.很多时候,在测试代码中花费的整个时间将小于DateTime.Now的分辨率,这将导致该测试的测量时间为零.
例如,当我在我的机器上运行以下测试时:
#define StopTime
using System;
using System.Diagnostics;
class C
{
static void Main() {
Random rg = new Random();
#if StopTime
Stopwatch stopTime = new Stopwatch();
#else
TimeSpan time = TimeSpan.Zero;
#endif
for(int i=0;i<1000000;++i) {
#if StopTime
stopTime.Start();
#else
DateTime start = DateTime.Now;
#endif
Convert.ToString(rg.Next(0, 99999999)).PadLeft(8, '0');
#if StopTime
stopTime.Stop();
#else
DateTime end = DateTime.Now;
time += end - start;
#endif
}
#if StopTime
Console.WriteLine(stopTime.Elapsed);
#else
Console.WriteLine(time);
#endif
}
}
Run Code Online (Sandbox Code Playgroud)
使用DateTime.Now方法(00:00:00.7680442)测量的时间大约是使用高分辨率秒表(00:00:01.6195441)测量的时间的一半