ByRef против производительности ByVal при передаче строк - PullRequest
4 голосов
/ 22 июля 2010

Чтение Что быстрее? ByVal или 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 ]

9 голосов
/ 22 июля 2010

Строки не копируются перед передачей.Строки являются ссылочными типами, даже если они ведут себя как типы значений.

Вы должны использовать все, что наиболее целесообразно в контексте ваших требований.(И если ваши требования оказываются примерно такими, как «необходимо сжимать каждую последнюю наносекунду производительности за счет всех других соображений», то вам, вероятно, следует взломать профилировщик, а не запрашивать стек переполнения!)безусловно, это то, о чем вам не нужно беспокоиться, и я сомневаюсь, что когда-либо будет существенная разница в производительности.Единственная ситуация, в которой я вижу какой-либо шанс на разницу, заключается в передаче больших типов значений.

2 голосов
/ 20 июля 2012

Я решил проверить это для себя, чтобы получить более «научный» ответ.Они одинаковые.Если я использую код ниже, ByVal примерно на 2% медленнее, чем ByRef.Однако, если я поменяю их местами, так что я синхронизирую ByRef с ByVal, то 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
0 голосов
/ 20 июля 2012

Чтобы понять поведение типов классов, включая строки, рассмотрите все параметры типа класса, переменные, поля, элементы массива и т. Д. Как содержащие «идентификаторы объектов».Если Foo является переменной типа string, оператор Foo = 12345.ToString(); создаст новый идентификатор объекта (гипотетически, идентификатор объекта # 197) и создаст новый объект типа string с этим идентификатором, удерживая пятьсимволы "12345".Затем он будет хранить Object ID#197 в переменной Foo.Если кто-то вызывает подпрограмму с параметром без ссылки param и передает ей Foo, то param будет локальной переменной, содержащей Object ID #197.Оператор param += "6"; создаст новый объект (например, Object ID # 521) типа string, содержащий шесть символов "123456" и сохранит Object ID #521 в param.Обратите внимание, что Foo по-прежнему содержит Object ID#197, а этот объект по-прежнему содержит пятисимвольную строку "12345".

Если param был передан ref, то оператор param += "6" будетсохранили Object ID #521 в Foo.Это все равно не привело бы к каким-либо заметным изменениям в Объекте № 197, за исключением, возможно, предоставления ему права на сборку мусора (если бы Foo была единственной ссылкой на Объект № 197, перезапись это означало бы, что больше не было бы никакой ссылкик этому объекту в любом месте вселенной).

Обратите внимание, что, как правило, довольно легко рассуждать о неизменных типах классов, таких как string, даже не думая с точки зрения идентификаторов объектов, поскольку это единственный способ изменить последовательностьСимволы, представленные строковой переменной, предназначены для хранения другого идентификатора объекта.Однако при работе с изменчивыми типами классов становится важным думать с точки зрения идентификаторов объектов.Передача переменной типа класса Car, а не ref, будет эквивалентна копированию VIN с одного листа бумаги на другой и передаче последнего листа бумаги некоторым работникам магазина и предложению им что-то с этим сделать.Если в первом документе первоначально была идентифицирована красная машина с VIN # 15934, то, когда рабочие закончили, первая бумага может идентифицировать синюю машину с VIN # 15934, но это будет та же машина.Ничто из того, что рабочие могли сделать с полученным им листом бумаги, и все, что они могли сделать с машиной, не изменило бы, какую машину упоминал первый документ.С другой стороны, передача параметра по ссылке была бы больше похожа на работу работника магазина с бумажкой, на которой был написан VIN, и на получение бумаги от них, когда они были готовы.Если работники могли вычеркнуть VIN и написать другой, тогда, когда они вернули листок бумаги, это могло относиться к той же машине или другой машине;если это относится к другому автомобилю, автомобиль, на который он первоначально ссылался, может быть изменен или не изменен, а автомобиль, на который ссылается бумага, может иметь или не иметь никакого сходства с оригиналом.

...