代码之家  ›  专栏  ›  技术社区  ›  Clément

传递字符串时的byref与byval性能

  •  4
  • Clément  · 技术社区  · 14 年前

    阅读 Which is faster? ByVal or ByRef? 我想知道里面的评论是否适用于 Strings 在性能方面。因为字符串是在传递之前被复制的,所以传递字符串是否更有效(如果被调用方不需要字符串过程的副本) ByRef ?

    谢谢,
    CFP。

    编辑: 考虑一下这段代码,这让我觉得有些抄袭正在进行:

    Sub Main()
        Dim ByValStr As String = "Hello World (ByVal)!"
        Dim ByRefStr As String = "Hello World (ByRef)!"
    
        fooval(ByValStr)
        fooref(ByRefStr)
    
        Console.WriteLine("ByVal: " & ByValStr)
        Console.WriteLine("ByRef: " & ByRefStr)
    
        Console.ReadLine()
    End Sub
    
    
    Sub fooval(ByVal Str As String)
        Str = "foobar"
    End Sub
    
    Sub fooref(ByRef Str As String)
        Str = "foobar"
    End Sub
    

    它输出:

    ByVal: Hello World (ByVal)!
    ByRef: foobar
    
    3 回复  |  直到 12 年前
        1
  •  9
  •   LukeH    14 年前

    不是 传递前已复制。字符串是引用类型,即使它们的行为有点像值类型。

    您应该在需求的上下文中使用最有意义的东西。(如果您的需求恰好是“必须以牺牲所有其他考虑因素为代价压缩最后一纳秒的性能”,那么您可能应该破解剖析器,而不是询问stackoverflow!)

    这几乎可以肯定是你不必担心的事情,我怀疑是否存在显著的性能差异。唯一能让我看到不同的情况就是传球的时候 大的 值类型。

        2
  •  2
  •   Stephen Oberauer    12 年前

    我决定自己检查一下,以得到一个更“科学”的答案。它们是一样的。如果我使用下面的代码,ByVal比ByRef慢2%。不过,如果我把它们交换一下,这样我就可以在ByVal之前对ByRef进行计时,那么ByRef就慢了2%。所以,在本例中,比byref或byval更重要的是它们的运行顺序:)

    Function CreateString()
    
        Dim i As Integer
        Dim str As String = ""
    
        For i = 1 To 10000
            str = str & "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        Next i
    
        Return str
    End Function
    
    Sub fooval(ByVal Str As String)
        Str = Str & "foobar"
    End Sub
    
    Sub fooref(ByRef Str As String)
        Str = Str & "foobar"
    End Sub
    
    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        Dim str As String = CreateString()
        Dim stopWatch As New Stopwatch
        Dim i As Integer
    
        stopWatch.Start()
        For i = 1 To 1000
            fooval(str)
        Next i
        stopWatch.Stop()
        Dim valtime As Long = stopWatch.ElapsedMilliseconds
    
        stopWatch.Restart()
        For i = 1 To 1000
            fooref(str)
        Next i
        stopWatch.Stop()
        Dim reftime As Long = stopWatch.ElapsedMilliseconds
    
        MsgBox("Val took " & valtime & " milliseconds and Ref took " & reftime & " milliseconds")
    End Sub
    
        3
  •  0
  •   supercat    12 年前

    要了解类类型(包括字符串)的行为,请将所有类类型参数、变量、字段和数组元素等视为持有“对象ID”。如果 Foo 是类型的变量 string ,声明 Foo = 12345.ToString(); 将创建新的对象ID(假设为对象ID 197),并创建类型为的新对象 一串 带着那个身份证,拿着五个字符 "12345" . 然后它会存储 Object ID#197 进入变量 . 如果调用带有非引用参数的例程 param 及格 然后, 帕拉姆 将是局部变量保持 Object ID #197 . 声明 param += "6"; 将创建一个字符串类型的新对象(例如,对象ID 521),其中包含六个字符 "123456" 商店 Object ID #521 进入之内 帕拉姆 . 注意 仍然持有 对象ID 197 ,该对象仍保留五个字符的字符串 “12345” .

    如果 帕拉姆 已经过去了 ref ,然后是声明 param += "6" 本来可以储存的 对象ID 521 进入之内 . 它仍然不会对对象197造成任何可观察的更改,除非它可能符合垃圾收集的条件(如果 如果是唯一一个对物体的引用197,覆盖它意味着宇宙中任何地方都不再存在对该物体的任何引用。

    请注意,对于不可变的类类型(如 一串 即使不考虑对象ID,因为更改字符串变量表示的字符序列的唯一方法是在其中存储不同的对象ID。但是,在处理可变类类型时,考虑对象ID变得非常重要。传递类类型的变量 Car 而不是参考号,这就相当于从一张纸条复制一个VIN到另一张纸条,然后将后一张纸条交给一些车间工人,并要求他们做些事情。如果第一篇论文最初用VIN 15934标识了一辆红色汽车,那么当工人们完成第一篇论文时,可能会用VIN 15934标识一辆蓝色汽车,但它是同一辆车。工人们对给他们的那张纸条无能为力,对那辆车也无能为力,他们都不会改变第一张纸提到的那辆车。另一方面,通过引用传递参数更像是车间工人写上VIN的一张纸,完成后从他们那里取回纸张。如果工人可以划掉VIN并写下另一个,那么当他们归还纸条时,可能是指同一辆车或不同的车;如果是指不同的车,那么最初所指的车可能已经或可能没有被修改过,而纸条所指的车可能或可能没有任何相似之处。原创。

    推荐文章