传递字符串时的 ByRef 与 ByVal 性能
阅读 哪个更快? 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
字符串在传递之前不会被复制。字符串是引用类型,尽管它们的行为有点像值类型。
您应该使用在您的需求背景下最有意义的任何内容。 (如果你的要求恰好是“必须牺牲所有其他考虑因素来压缩性能的最后一纳秒”,那么你可能应该破解分析器而不是在 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.
我决定亲自检查一下,以获得更“科学”的答案。他们是一样的。如果我使用下面的代码,ByVal 比 ByRef 慢大约 2%。但是,如果我交换它们,以便在 ByVal 之前对 ByRef 进行计时,则 ByRef 大约会慢 2%。因此,在这种情况下,实际上比 ByRef 或 ByVal 更重要的是它们的运行顺序:)
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 :)
要理解类类型(包括字符串)的行为,请将所有类类型参数、变量、字段和数组元素等视为保存“对象 ID”。如果
Foo
是string
类型的变量,则语句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 typestring
, the statementFoo = 12345.ToString();
will create a new object id (hypothetically, Object ID#197), and create a new object of typestring
with that id, holding the five characters"12345"
. It will then storeObject ID#197
into the variableFoo
. If one calls a routine with a non-ref parameterparam
, and passesFoo
to it, thenparam
will be a local variable holdingObject ID #197
. The statementparam += "6";
would create a new object (e.g. Object ID #521), of type string, holding the six characters"123456"
and storeObject ID #521
intoparam
. Note thatFoo
still holdsObject ID#197
, and that object still holds the five-character string"12345"
.If
param
had been passed byref
, then the statementparam += "6"
would have storedObject ID #521
intoFoo
. It still would not have caused any observable change to Object #197, except perhaps to make it eligible for garbage collection (ifFoo
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 typeCar
, 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.