异步随机字母生成太快

时间:2014-06-06 12:04:11

标签: c# asynchronous random generator

我知道发电机存在问题,因为它们有时太快,最终会产生两次相同的字符,或根本不产生。我正在创建一个生成随机字符的程序,我想要包含一个我将使用异步生成实现的进度条。

问题在于它不能正确生成,因为它生成得太快。我告诉它生成3组字符,它会做1或5组,它会做2。

如何减慢速度并允许它以异步方式生成,或者如何以其他方式实现工作进度条?

这是我的一些代码:

private void btnGenerate_Click(object sender, EventArgs e) {
    Random rand = new Random();
    string result;
    bool failed = false;

    int amount = Convert.ToInt32(numMassGen.Value),
        initialAmount = amount;

     while(0 < amount--) {
        result = Generate(rand).Result;

        if(result != "failed") {
            WriteToFile(result, initialAmount - amount);
            statusText.Text = "Finished generating and saving " + (initialAmount - amount) + "/" + initialAmount + " keys."; 
        }
        else {
            UpdateStatus("Not enough options selected for this length.");
            failed = true;
            break;
        }
    }

    if(!failed) {
        UpdateStatus("Finished generating and saving " + numMassGen.Value + " keys.");
    }
}

private Task WriteToFile(string result, int completed) {
    return WriteToFileAsync(result);
}

private async Task WriteToFileAsync(string result) {
    byte[] resultEncoded = Encoding.UTF8.GetBytes(result + Environment.NewLine);

    using(FileStream stream = new FileStream(txtSaveLocation.Text,
        FileMode.Append,
        FileAccess.Write,
        FileShare.None,
        bufferSize: 4096,
        useAsync: true)) {
            await stream.WriteAsync(resultEncoded, 0, resultEncoded.Length);
    }
}

// This method's probably crude, it's a little old and I don't know
// how to improve it.
// This is also where the problems occur. When I step through this code,
// it's slowing down the random generation.
// When I run it normally, it's too fast and skips generating.
private async Task<string> GenerateAsync(Random rand) {
    string sAll = "", result = "", sLower, sUpper, sNumbers, sHyphen, sUnderscore, sSpace, sSpecial, sBrackets;
    int length = Convert.ToInt32(numSections.Value) * Convert.ToInt32(numCharacters.Value),
        initialLength = length;
    char character;

    sLower = "abcdefghijklmnopqrstuvwxyz";
    sUpper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    sNumbers = "0123456789";
    sHyphen = "-";
    sUnderscore = "_";
    sSpace = " ";
    sSpecial = "`~!@#$%^&*()+=\\|/?.,;:'\"";
    sBrackets = "()[]{}<>";

    if(Properties.Settings.Default.charUppercase)
        sAll += sUpper;
    if(Properties.Settings.Default.charLowercase)
        sAll += sLower;
    if(Properties.Settings.Default.charNumbers)
        sAll += sNumbers;
    if(Properties.Settings.Default.charUnderscore)
        sAll += sUnderscore;
    if(Properties.Settings.Default.charSpace)
        sAll += sSpace;
    if(Properties.Settings.Default.charSpecial)
        sAll += sSpecial;
    if(Properties.Settings.Default.charBrackets)
        sAll += sBrackets;

    while(0 < length) {
        if(sAll.Length == 0) {
            return "failed";
        }

        character = sAll[rand.Next(sAll.Length)];

        if(Properties.Settings.Default.charRepeat) {
            sAll = sAll.Remove(sAll.IndexOf(character), 1);
        }

        if((length % Properties.Settings.Default.secCharacters == 0) && (length != 0) && (length != initialLength)) {
            result += sHyphen;
        }

        result += character;

        length--;
    }

    return result;
}

1 个答案:

答案 0 :(得分:3)

来自您的评论

  

为什么我的随机生成的字符有时会连续出现两次,有些答案说这是因为进程运行得太快而且需要时间来生成另一个字符。

如果您在短时间内创建Random类的新实例并从中请求新值(通常在循环中),通常会发生这种情况。在这种情况下,每个新的Random对象可以从当前系统时钟获得相同的种子,并且可以产生相同的伪随机数。这就是大多数伪随机生成器按设计工作的方式。

但是,如果你使用 Random类的相同实例(这是你应该做的),这是不可能的(有一个注释,见下文)。这是由于Random类能够考虑其先前的状态。

请注意, random不等于唯一

伪随机数发生器绝对有可能产生相同数字的序列。例如,如果您只能选择0或1,则RNG 可能生成仅包含零的序列:0, 0, 0, 0, 0, 0, 0, 0, 0, ...。每个为0的概率为50%,这可能在一些长期运行的实验中产生一个包含全零的所需长度序列。这可能需要花费很多时间,但这是可能的。

回答你的问题:

  • 了解 random 之间的区别(这允许重复,但使用统一分发为您提供下一个值)和 unique (不允许重复,可以使用任何分发)
  • 仅使用Random课程的单个实例或更好RNGCryptoServiceProvider
  • 生成速度必须与正确实施无关,因为下一个值将取决于先前的状态
  • 让它同步工作,然后切换到异步(但坦率地说,这里不需要异步)
  • Random不是线程安全的