Что быстрее? ByVal или ByRef?

В VB.NET, который быстрее использовать для аргументов метода,ByVal или жеByRef?

Кроме того, что потребляет больше ресурсов во время выполнения (ОЗУ)?

Я прочиталэтот вопрос, но ответы не применимы или недостаточно конкретны.

 GameAlchemist07 сент. 2011 г., 19:35
Другой ответ может быть следующим: если выбор ByVal / ByRef становится критичным для скорости приложения, возможно, настало время сделать меньше вызовов функций ...

Ответы на вопрос(7)

и от объекта и использования памяти.

Результат кажется убедительным, что ByVal всегда побеждает, ресурс зависит от того, собирают ли память или меньше (только 4.5.1)

Public Structure rStruct
    Public v1 As Integer
    Public v2 As String
End Structure

Public Class tClass
    Public v1 As Integer
    Public v2 As String
End Class



Public Sub Method1(ByRef s As String)
    Dim c As String = s
End Sub

Public Sub Method2(ByVal s As String)
    Dim c As String = s
End Sub

Public Sub Method3(ByRef i As Integer)
    Dim x As Integer = i
End Sub

Public Sub Method4(ByVal i As Integer)
    Dim x As Integer = i
End Sub

Public Sub Method5(ByVal st As rStruct)
    Dim x As rStruct = st
End Sub

Public Sub Method6(ByRef st As rStruct)
    Dim x As rStruct = st
End Sub


Public Sub Method7(ByVal cs As tClass)
    Dim x As tClass = cs
End Sub

Public Sub Method8(ByRef cs As tClass)
    Dim x As tClass = cs
End Sub
Sub DoTest()

    Dim s As String = "Hello World!"
    Dim cs As New tClass
    cs.v1 = 1
    cs.v2 = s
    Dim rt As New rStruct
    rt.v1 = 1
    rt.v2 = s
    Dim k As Integer = 5




    ListBox1.Items.Add("BEGIN")

    Dim t As New Stopwatch
    Dim gt As New Stopwatch

    If CheckBox1.Checked Then
        ListBox1.Items.Add("Using Garbage Collection")
        System.Runtime.GCSettings.LargeObjectHeapCompactionMode = System.Runtime.GCLargeObjectHeapCompactionMode.CompactOnce
        GC.Collect()
        GC.WaitForPendingFinalizers()
        GC.Collect()
        GC.GetTotalMemory(False)
    End If

    Dim d As Double = GC.GetTotalMemory(False)

    ListBox1.Items.Add("Free Memory:   " & d)

    gt.Start()
    t.Reset()
    t.Start()
    For i As Integer = 0 To 100000000
        Method1(s)
    Next
    t.Stop()

    ListBox1.Items.Add("Reference Type - ByRef " & t.ElapsedMilliseconds)

    t.Reset()
    t.Start()
    For i As Integer = 0 To 100000000
        Method2(s)
    Next
    t.Stop()

    ListBox1.Items.Add("Reference Type - ByVal " & t.ElapsedMilliseconds)

    t.Reset()
    t.Start()
    For i As Integer = 0 To 100000000
        Method3(i)
    Next
    t.Stop()

    ListBox1.Items.Add("Value Type - ByRef " & t.ElapsedMilliseconds)

    t.Reset()
    t.Start()
    For i As Integer = 0 To 100000000
        Method4(i)
    Next
    t.Stop()

    ListBox1.Items.Add("Value Type - ByVal " & t.ElapsedMilliseconds)

    t.Reset()
    t.Start()

    For i As Integer = 0 To 100000000
        Method5(rt)
    Next
    t.Stop()

    ListBox1.Items.Add("Structure Type - ByVal " & t.ElapsedMilliseconds)

    t.Reset()
    t.Start()

    For i As Integer = 0 To 100000000
        Method6(rt)
    Next
    t.Stop()

    ListBox1.Items.Add("Structure Type - ByRef " & t.ElapsedMilliseconds)

    t.Reset()
    t.Start()

    For i As Integer = 0 To 100000000
        Method7(cs)
    Next
    t.Stop()

    ListBox1.Items.Add("Class Type - ByVal " & t.ElapsedMilliseconds)

    t.Reset()
    t.Start()

    For i As Integer = 0 To 100000000
        Method8(cs)
    Next
    t.Stop()
    gt.Stop()

    ListBox1.Items.Add("Class Type - ByRef " & t.ElapsedMilliseconds)
    ListBox1.Items.Add("Total time " & gt.ElapsedMilliseconds)
    d = GC.GetTotalMemory(True) - d
    ListBox1.Items.Add("Total Memory Heap consuming (bytes)" & d)


    ListBox1.Items.Add("END")

End Sub


Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click


    DoTest()

End Sub
 Ziriax04 янв. 2017 г., 16:10
Вы передаете очень маленькую структуру по значению, очевидно, что в этом случае ссылка будет медленнее. Не могли бы вы также добавить GUID к вашей структуре и классу и попробовать еще раз?

Это потому, что передается указатель на указатель. Любой доступ к полям объекта требует разыменования дополнительного указателя, для завершения которого потребуется несколько дополнительных тактов.

Если вы передаете тип значения, тогда byref может быть быстрее, если структура имеет много членов, потому что она передает только один указатель, а не копирует значения в стек. С точки зрения доступа к элементам, byref будет медленнее, потому что он должен делать разыменование дополнительного указателя (sp-> pValueType-> member vs sp-> member).

Большую часть времени в VB вам не нужно беспокоиться об этом.

В .NET редко встречаются типы значений с большим количеством членов. Они обычно маленькие. В этом случае передача типа значения не отличается от передачи нескольких аргументов в процедуру. Например, если бы у вас был код, который передавал объект Point по значению, его perf был бы таким же, как метод, принимающий значения X и Y в качестве параметров. Видение DoSomething (x как целое число, y как целое число), вероятно, не вызовет проблем с перфорированием. На самом деле, вы, вероятно, никогда бы не подумали об этом дважды.

Если вы сами определяете типы больших значений, то вам, вероятно, следует пересмотреть вопрос о преобразовании их в ссылочные типы.

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

Таким образом, вместо того, чтобы сосредоточиться на том, является ли byval или byref более быстрым, я бы порекомендовал вам сосредоточиться на том, что дает вам семантику, которая вам нужна. В общем случае, рекомендуется использовать byval, если вам не нужен byref. Это делает программу намного проще для понимания.

я расскажу, что я знаю о скомпилированных языках. этоне относится к ссылочным типами может быть не совсем точным в отношении типов значений. Если вы не знаете разницу между типами значений и ссылочными типами, вам не следует это читать. Я полагаю, 32-битный x86 (с 32-битными указателями).

При передаче значений, меньших 32-битных, в стеке по-прежнему используется 32-битный объект. Часть этого объекта будет «неиспользована» или «заполнена». Передача таких значений не использует меньше памяти, чем передача 32-битных значений.Передача значений больше 32-битных будет занимать больше места в стеке, чем указатель, и, вероятно, больше времени на копирование.Если объект передается по значению, вызываемый объект может извлечь объект из стека. Если объект передается по ссылке, вызываемый объект должен сначала извлечь адрес объекта из стека, а затем получить значение объекта из другого места. По значению означает на одну выборку меньше, верно? Ну, на самом деле выборка должна быть сделана вызывающим абонентом - однако вызывающему, возможно, уже пришлось получать выборку по разным причинам, и в этом случае выборка сохраняется.Очевидно, что любые изменения, внесенные в значение по ссылке, должны быть сохранены обратно в ОЗУ, тогда как параметр по значению может быть отброшен.Лучше передавать по значению, чем передавать по ссылке только для того, чтобы скопировать параметр в локальную переменную и не прикасаться к нему снова.

Вердикт:

Гораздо важнее понять, что на самом деле делают для вас ByVal и ByRef, и понять разницу между значениями и ссылочными типами, чем думать о производительности. Правило номер один заключается виспользуйте тот метод, который больше подходит вашему коду.

Для типов больших значений (более 64 бит) передайте по ссылке, если нет преимущества перед передачей по значению (например, более простой код, «это просто имеет смысл» или согласованность интерфейса).

Для меньших типов значений механизм передачи не имеет большого значения для производительности, и в любом случае трудно предсказать, какой метод будет быстрее, так как он зависит от размера объекта, того, как вызывающий и вызывающий используют объект, и даже из соображений кэширования. , Просто делайте все, что имеет смысл для вашего кода.

Guid довольно большой), передача параметра по ссылке может быть немного быстрее. В других случаях могут бытьБольше копирование и т. д. при передаче по ссылке, а не по значению - например, если у вас есть параметр байта, то один байт явно меньше четырех или восьми байтов, которые указатель получит, если вы передадите его по ссылке.,

На практике вы почти никогда не должны беспокоиться об этом. Напиши больше всегоудобочитаемый код возможен, что почти всегда означает передачу параметров по значению вместо ссылки. Я использую ByRef очень редко.

Если вы хотите улучшить производительность и думаете, что ByRef поможет вам,пожалуйста тщательно оцените его (в вашей конкретной ситуации), прежде чем совершать его.

РЕДАКТИРОВАТЬ: я отмечаю в комментариях к другому (ранее принятому, теперь удаленному) ответу, что существует большое недопонимание того, что означает ByRef против ByVal, когда речь идет о типах значений. у меня естьстатья о передаче параметров которая за последние годы стала популярной - это терминология C #, но те же понятия применимы и к VB.NET.

ByVal создает копию переменной, тогда какByRef передает указатель Поэтому я бы сказал, чтоByVal медленнее (из-за времени, необходимого для копирования) и использует больше памяти.

 pyon02 янв. 2009 г., 23:05
Фактически рассмотрим любой тип, размер которого меньше размера указателя. (Короткая, например)
 Jon Skeet02 янв. 2009 г., 23:00
Это только догадки, хотя. Рассмотрим параметр байта - а затем рассмотрим размер указателя ...
 bruceatk03 янв. 2009 г., 17:09
Теперь представьте строку, которая содержит содержимое большого текстового файла. Нет догадок ByRef быстрее. Я предполагаю, что это не имеет значения, когда размеры маленькие.

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

Решение Вопроса

наний о том, как они работают.не по скорости.

http://www.developer.com/net/vb/article.php/3669066

В ответ на комментарий Слау -

Который потребляет больше ресурсов во время выполнения?

Параметры передаются в стек. Стек очень быстрый, потому что его выделение памяти - просто приращение указателя, чтобы зарезервировать новый «кадр» или «запись выделения». Большинство параметров .NET не превышают размер машинного регистра настолько мало, если для передачи параметров используется какое-либо «стековое» пространство. На самом деле базовые типы и указатели размещаются в стеке. Размер стека в .NET ограничен 1 МБ. Это должно дать вам представление о том, как мало ресурсов потребляется при передаче параметров.

Вы можете найти эту серию статей интересными:

Повышение производительности за счет распределения стеков (.NET Memory Management: часть 2)

Что быстрее? ByVal или ByRef.

В лучшем случае сложно измерить точно и точно - в зависимости от контекста вашего измерения, но эталонный тест, который я написал, вызывая метод 100 миллионов раз, дал следующее:

Тип ссылки - пройдено по ссылке: 420 мсТип ссылки - пройдено ByVal: 382 мсТип значения - пройдено по ссылке: 421 мсТип значения - пройдено ByVal: 416 мс
Public Sub Method1(ByRef s As String)
    Dim c As String = s
End Sub

Public Sub Method2(ByVal s As String)
    Dim c As String = s
End Sub

Public Sub Method3(ByRef i As Integer)
    Dim x As Integer = i
End Sub

Public Sub Method4(ByVal i As Integer)
    Dim x As Integer = i
End Sub

Sub Main()

    Dim s As String = "Hello World!"
    Dim k As Integer = 5

    Dim t As New Stopwatch

    t.Reset()
    t.Start()
    For i As Integer = 0 To 100000000
        Method1(s)
    Next
    t.Stop()

    Console.WriteLine("Reference Type - ByRef " & t.ElapsedMilliseconds)

    t.Reset()
    t.Start()
    For i As Integer = 0 To 100000000
        Method2(s)
    Next
    t.Stop()

    Console.WriteLine("Reference Type - ByVal " & t.ElapsedMilliseconds)

    t.Reset()
    t.Start()
    For i As Integer = 0 To 100000000
        Method3(i)
    Next
    t.Stop()

    Console.WriteLine("Value Type - ByRef " & t.ElapsedMilliseconds)

    t.Reset()
    t.Start()
    For i As Integer = 0 To 100000000
        Method4(i)
    Next
    t.Stop()

    Console.WriteLine("Value Type - ByVal " & t.ElapsedMilliseconds)

    Console.ReadKey()

End Sub

Комментирование переменной и присваивания в каждом методе -

Тип ссылки - пройдено по ссылке: 389 мсТип ссылки - пройдено ByVal: 349 мсТип значения - пройдено ByRef: 416 мсТип значения - пройдено ByVal: 385 мс

Можно сделать вывод, что передача ссылочных типов (строк, классов) ByVal сэкономит некоторое время. Можно также сказать, что передача значений типа (целое число, байт) - ByVal сэкономит некоторое время.

Снова время незначительно в великой схеме вещей. Что более важно, это правильно использовать ByVal и ByRef и понимать, что происходит «за кулисами». Алгоритмы, реализованные в ваших подпрограммах, наверняка будут влиять на время выполнения вашей программы во много раз больше.

 Jon Skeet02 янв. 2009 г., 23:03
К сожалению, сегодня не осталось ни одного голоса, но в остальном мне +1.
 supercat28 июн. 2012 г., 00:51
Время, необходимое для передачи типа значенияByVal будет варьироваться в зависимости от размера рассматриваемого типа значения. Время, необходимое для прохожденияByRef не буду. Если типы значений велики, передачаByRef может быть намного быстрее Обратите внимание, что даже очень большие типы значений (тысячи байтов) могут быть очень производительными, если можно избежать их передачи по значению или ненужного копирования.
 ctacke02 янв. 2009 г., 23:13
Здесь, здесь. Если вы хотите добиться успеха, изменив это, вы, вероятно, не знаете, какого черта вы делаете.
 dr. evil03 янв. 2009 г., 00:58
ответ правильный, но это был не вопрос, не так ли? Почему мы предполагаем, что новичок не знает об этом в любом случае?

Ваш ответ на вопрос