【问题标题】:Generate Random String is very slow生成随机字符串非常慢
【发布时间】:2014-09-03 12:59:59
【问题描述】:

我喜欢在 vb.net 中生成一个随机字符串。 我已经写了一个函数来完成这项工作:

但是这种生成随机字符串的方式非常慢,对于大约 5 个文本框,生成字符串需要将近一秒钟。 我怎样才能加快我的一段代码?

感谢每一个帮助:)

【问题讨论】:

  • 字符串生成的时间有多长?
  • 随机字符串只有20位数。
  • 这应该不会很慢。一定还有其他一些瓶颈。尝试一个控制台应用程序并将此代码粘贴到其中。还要注意两个变量????在您的代码之前和之后减少时间(以毫秒为单位)。然后运行以检查这段代码花费了多少时间。
  • 编辑:如果您希望函数生成1,请将rnd.Next(1 , 62) 更改为rnd.Next(0 , 62),因为minValue 是包容性的,maxValue独有的乙>。注意:vb.net 中的数组是从零开始的。
  • 我同意比约恩的观点。此外,您不需要对 maxval(62) 进行硬编码,只需使用 CharSet.Length。如果您在集合中添加/删除字符,则无需更改任何其他内容。

标签: vb.net string text random numbers


【解决方案1】:

您也可以使用Random.NextBytes方法如下:

Dim rnd As New System.Random

Private Function NewRandomString(ByVal length As Integer) As String
    If length <= 0 Then Return ""
    Dim CharSet As String = "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
    Dim GenRandomStr As New StringBuilder
    Dim RandomBytes(length - 1) As Byte
    rnd.NextBytes(RandomBytes)

    For i As Integer = 0 To length - 1
        GenRandomStr.Append(CharSet(RandomBytes(i) Mod CharSet.Length))
    Next

    Return GenRandomStr.ToString
End Function

要比较这个函数的速度,使用下面的代码:

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Dim Stopwatch As New Stopwatch
    Stopwatch.Start()

    For i As Integer = 1 To 100000
        RandomString(200)
    Next

    Stopwatch.Stop()
    MsgBox("Original time [" & Stopwatch.Elapsed.ToString() & "]")

    Stopwatch.Reset()
    Stopwatch.Start()

    For i As Integer = 1 To 100000
        NewRandomString(200)
    Next

    Stopwatch.Stop()
    MsgBox("New time [" & Stopwatch.Elapsed.ToString() & "]")
End Sub

对于 100000 次迭代(在 i7 4770k 上),我得到以下时间:

Original time [00:00:00.5434907]
     New time [00:00:00.3569711]

快 34%

【讨论】:

    【解决方案2】:

    这是我的方法:

    Dim Randomizer As New Random
    
    ' Get Random String
    ' // By Elektro
    '
    ' Usage Examples :
    ' MsgBox(GetRandomString("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", 10))
    ' MsgBox(GetRandomString("abcdefghijklmnopqrstuvwxyz", 10, True))
    '
    ''' <summary>
    ''' Gets a random string.
    ''' </summary>
    ''' <param name="CharacterSet">Indicates the characters to randomize.</param>
    ''' <param name="StringLength">Indicates the resulting string length.</param>
    ''' <param name="RandomizeCase">If set to <c>true</c>, lower-case and upper-case are randomized.</param>
    ''' <returns>System.String.</returns>
    ''' <exception cref="System.Exception">
    ''' CharacterSet is empty.
    ''' or
    ''' String-Length must be greater than 0.
    ''' </exception>
    Private Function GetRandomString(ByVal CharacterSet As Char(),
                                     ByVal StringLength As Integer,
                                     Optional ByVal RandomizeCase As Boolean = False) As String
    
        Select Case CharacterSet.Count
    
            Case Is = 0
                Throw New Exception("CharacterSet is empty.")
    
            Case Is = 1
                Return New String(CharacterSet.First, Math.Abs(StringLength))
    
            Case Else
    
                Select Case StringLength
    
                    Case Is < 1
                        Throw New Exception("String-Length must be greater than 0.")
    
                    Case Else
    
                        Dim CharSetLength As Integer = CharacterSet.Length
                        Dim CharSB As New System.Text.StringBuilder
    
                        Do Until CharSB.Length = StringLength
    
                            If Not RandomizeCase Then
                                CharSB.Append(CharacterSet(Randomizer.Next(0, CharSetLength)))
    
                            Else
    
                                Select Case Randomizer.Next(0, 2)
    
                                    Case 0 ' Lower-Case
                                        CharSB.Append(Char.ToLower(CharacterSet(Randomizer.Next(0, CharSetLength))))
    
                                    Case 1 ' Upper-Case
                                        CharSB.Append(Char.ToUpper(CharacterSet(Randomizer.Next(0, CharSetLength))))
    
                                End Select
    
                            End If '/ Not RandomizeCase
    
                        Loop '/ CharSB.Length = StringLength
    
                        Return CharSB.ToString
    
                End Select '/ StringLength
    
        End Select '/  CharacterSet.Count
    
    End Function
    

    【讨论】:

      【解决方案3】:

      所以我测试了它。不到一秒即可生成 100、200 个字符串。

      Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
          Dim stpw As Stopwatch = Stopwatch.StartNew
          For x As Integer = 1 To 100
              TextBox1.Text = RandomString(200)
              TextBox1.Refresh()
          Next
          stpw.Stop()
          Debug.WriteLine(stpw.Elapsed)
      End Sub
      
      Dim prng As New Random
      Private Function RandomString(desiredLength As Integer) As String
          Dim CharSet As String = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
          Dim rv As New System.Text.StringBuilder
      
          For ct As Integer = 1 To desiredLength
              rv.Append(CharSet(prng.Next(0, CharSet.Length)))
          Next
          Return rv.ToString
      End Function
      

      编辑:新测试,不到一毫秒,即使按钮被尽快按下。

      Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
          Dim stpw As Stopwatch = Stopwatch.StartNew
          TextBox1.Text = RandomString(200)
          TextBox2.Text = RandomString(200)
          TextBox3.Text = RandomString(200)
          stpw.Stop()
          Debug.WriteLine(stpw.Elapsed)
      End Sub
      

      【讨论】:

      • 嗯,很好!但是当我像这样将这个随机函数分配给我的文本框文本时:puu.sh/a9pqb/b797cc6e5f.png 我仍然不能真正快速地生成数字。当我非常快地单击按钮时,它仍然不会每次都生成数字:/
      • 我将您的测试添加到此。我的猜测是你有其他事件连接到文本框。
      • 不,没有其他事件。
      • 我的测试使用更多字符,运行时间不到一毫秒。你的测试没有,所以它必须是别的东西。我认为 RandomString 方法不是问题。 FWIW - 我还使用 .ElementAt 进行了测试,这不是必需的,结果相同。
      【解决方案4】:

      试试看:

      Dim chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz"
      Dim random = New Random(Guid.NewGuid().GetHashCode())
      Dim randomString = New String(Enumerable.Repeat(chars, 20).[Select](Function(s) s(random.[Next](s.Length))).ToArray())
      Return randomString
      

      【讨论】:

      • 我不明白为什么人们觉得需要播种随机数生成器。
      • 你的意思是伪随机 :)
      • LINQ 查询速度不快
      【解决方案5】:

      我不熟悉 VB 及其语法,但这里有一些您可以转换的 c# 代码。我不确定这会快多少。

          var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
          var random = new Random(Guid.NewGuid().GetHashCode());
          var randomString = new string(
              Enumerable.Repeat(chars, 20)
                        .Select(s => s[random.Next(s.Length)])
                        .ToArray());
          return randomString ;
      

      【讨论】:

      • LINQ 查询速度不快
      猜你喜欢
      • 2015-07-28
      • 2017-08-01
      • 2011-06-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多