【问题标题】:Async random letter generation too fast异步随机字母生成太快
【发布时间】:2014-07-27 16:47:20
【问题描述】:

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

问题在于它无法正确生成,因为它生成得太快了。我会告诉它生成 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;
}

【问题讨论】:

  • 如果可能的话,你可以锁定一个对象。或者你需要建立一个节流机制。更多地取决于您的系统设计
  • 告诉我们,你到目前为止尝试了什么。
  • 我不知道你在说什么。可以发一些代码吗?
  • 完全不清楚你在说什么。您在哪里知道“生成器两次生成相同的字符”。你的假设的来源是什么?
  • @Samuel 对此感到非常抱歉......我度过了艰难的一天。我已经发布了一些(希望是清晰的)代码并在一些 cmets 中进行了解释。我之前问过一个问题,或者谷歌了一下,为什么我的随机生成的字符有时会连续出现两次,有些答案说这是因为进程运行得太快,需要时间来生成另一个字符。

标签: c# asynchronous random generator


【解决方案1】:

来自您的评论

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

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

但是,如果您使用Random 类的相同实例(这是您应该做的),这是不可能的(请注意,见下文)。这是因为 Random 类能够考虑其先前的状态。

请注意,随机不等于唯一

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

回答你的问题:

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

【讨论】:

  • 我将如何安全地执行此操作?我真的想生成完全随机的东西——或者那是不可能的?
  • @Abluescarab 如果您想要强烈的随机噪声,只需在 Windows 上使用 RNGCryptoServiceProvider。有提供良好噪音的 3rd 方库。我不能推荐一个确切的,但我认为如果你搜索 cryptographic random number generator open source c# 这应该会让你继续前进。
猜你喜欢
  • 1970-01-01
  • 2021-09-23
  • 2014-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多