传递字符串时的 ByRef 与 ByVal 性能

发布于 2024-09-10 18:40:35 字数 815 浏览 11 评论 0原文

阅读 哪个更快? ByVal 还是 ByRef? 让我想知道其中的注释在性能方面是否适用于 String。由于字符串在传递之前会被复制,因此传递字符串 ByRef 不是更高效(如果被调用者不需要字符串副本)吗?

谢谢,
金融理财师。

编辑:考虑这段代码,这让我觉得正在进行某种复制:

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

Reading Which is faster? ByVal or ByRef? made me wonder whether the comments in there did apply to Strings in terms of performance. Since strings are copied before being passed, isn't it much more efficient (if the callee doesn't need a copy of string course) to pass strings ByRef?

Thanks,
CFP.

Edit: Consider this code, which made me think there was some kind of copy going on:

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

It outputs:

ByVal: Hello World (ByVal)!
ByRef: foobar

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

葬心 2024-09-17 18:40:35

字符串在传递之前不会被复制。字符串是引用类型,尽管它们的行为有点像值类型。

您应该使用在您的需求背景下最有意义的任何内容。 (如果你的要求恰好是“必须牺牲所有其他考虑因素来压缩性能的最后一纳秒”,那么你可能应该破解分析器而不是在 stackoverflow 上询问!)

这几乎肯定是你不做的事情不需要担心,而且我怀疑是否存在显着的性能差异。我能看到任何差异的唯一情况是传递值类型时。

Strings are not copied before being passed. Strings are reference types, even though they behave somewhat like value types.

You should use whatever makes the most sense in the context of your requirements. (And if your requirements happen to be something like "must squeeze every last nanosecond of performance at the expense of all other considerations" then you should probably crack out the profiler rather than asking on stackoverflow!)

This is almost certainly something that you don't need to worry about, and I doubt if there's ever a significant performance difference. The only situation where I can see any chance of a difference would be when passing big value types.

夏花。依旧 2024-09-17 18:40:35

我决定亲自检查一下,以获得更“科学”的答案。他们是一样的。如果我使用下面的代码,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

I decided to check this for myself, to get a more "scientific" answer. They are the same. If I use the code below, ByVal is about 2% slower than ByRef. If, however, I swap them around, so that I'm timing ByRef before ByVal, then ByRef is about 2% slower. So, what actually matters more than ByRef or ByVal in this case is the order in which they run :)

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
最近可好 2024-09-17 18:40:35

要理解类类型(包括字符串)的行为,请将所有类类型参数、变量、字段和数组元素等视为保存“对象 ID”。如果 Foostring 类型的变量,则语句 Foo = 12345.ToString(); 将创建一个新的对象 id(假设为 Object ID#197),并使用该 id 创建一个 string 类型的新对象,其中包含五个字符 “12345”。然后它将把Object ID#197存储到变量Foo中。如果使用非引用参数 param 调用例程,并将 Foo 传递给它,则 param 将是一个保存 的局部变量>对象 ID #197。语句 param += "6"; 将创建一个字符串类型的新对象(例如对象 ID #521),包含六个字符 "123456" 并存储 < code>对象 ID #521 到 param 中。请注意,Foo 仍然保存Object ID#197,并且该对象仍然保存五个字符的字符串“12345”

如果 param 已通过 ref 传递,则语句 param += "6" 将存储对象 ID #521 到 Foo 中。它仍然不会对对象 #197 造成任何可观察到的变化,除了可能使其符合垃圾回收条件(如果 Foo 是对对象 #197 的唯一引用,覆盖它意味着将有宇宙中任何地方都不再存在对该物体的任何引用)。

请注意,即使不考虑对象 ID,通常也很容易推理出像 string 这样的不可变类类型,因为更改字符串变量表示的字符序列的唯一方法是存储那里有不同的对象 ID。然而,在处理可变类类型时,根据对象 ID 进行思考变得至关重要。传递类类型 Car 的变量(而不是通过 ref)相当于将 VIN 从一张纸条复制到另一张纸条,然后将后一张纸条交给一些商店工作人员,并要求他们用它做点什么。如果第一篇论文最初识别出一辆 VIN#15934 的红色汽车,那么当工作人员完成后,第一篇论文可能会识别出一辆 VIN#15934 的蓝色汽车,但它是同一辆车。工人们无法对他们收到的纸条进行任何操作,也无法对汽车进行任何操作,都不会改变第一份纸条所指的汽车。另一方面,通过引用传递参数更像是车间工作人员拿到一张写有 VIN 的纸,并在完成后从他们那里取回这张纸。如果工人们可以把VIN划掉,再写一个,那么当他们退回纸条时,它可能指的是同一辆车,也可能是另一辆车;如果它指的是不同的汽车,那么它最初提到的汽车可能已经或可能没有被修改,并且本文最终提到的汽车可能与原始汽车有任何相似之处,也可能没有任何相似之处。

To understand the behavior of class-types, including strings, regard all class-type parameters, variables, fields, and array elements, etc. as holding "object ids". If Foo is a variable of type string, the statement Foo = 12345.ToString(); will create a new object id (hypothetically, Object ID#197), and create a new object of type string with that id, holding the five characters "12345". It will then store Object ID#197 into the variable Foo. If one calls a routine with a non-ref parameter param, and passes Foo to it, then param will be a local variable holding Object ID #197. The statement param += "6"; would create a new object (e.g. Object ID #521), of type string, holding the six characters "123456" and store Object ID #521 into param. Note that Foo still holds Object ID#197, and that object still holds the five-character string "12345".

If param had been passed by ref, then the statement param += "6" would have stored Object ID #521 into Foo. It still would not have caused any observable change to Object #197, except perhaps to make it eligible for garbage collection (if Foo had been the only reference to Object #197, overwriting it would mean that there would no longer exist any reference to that object anywhere in the universe).

Note that it's generally pretty easy to reason about immutable class types like string, even without thinking in terms of Object IDs, since the only way to change the sequence of characters represented by a string variable is to store a different Object ID there. Thinking in terms of Object IDs becomes essential, however, when dealing with mutable class types. Passing a variable of class type Car, not by ref, would be equivalent to copying a VIN from one slip of paper to another, and handing the latter slip of paper to some shop workers, and asking them to do something with it. If the first paper originally identified a red car with VIN#15934, then when the workers were done the first paper might identify a blue car with VIN#15934, but it would be the same car. Nothing the workers could do with the slip of paper they were given, nor anything they could do with the car, would change which car the first paper referred to. On the other hand, passing the parameter by reference would be more like the shop workers a piece of paper with the VIN written on it, and getting the paper back from them when they were done. If the workers could cross out the VIN and write another, then when they returned the slip of paper it might refer to the same car or a different car; if it refers to a different car, the car to which it originally referred may or may not have been modified, and the car to which the paper ends up referring may or may not bear any resemblance to the original.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文