В VB.NET, который быстрее используется для аргументов метода, ByVal
или ByRef
?
Кроме того, который потребляет больше ресурсов во время выполнения (ОЗУ)?
Я прочитал этот вопрос, но ответы не применимы или достаточно конкретны.
В VB.NET, который быстрее используется для аргументов метода, ByVal
или ByRef
?
Кроме того, который потребляет больше ресурсов во время выполнения (ОЗУ)?
Я прочитал этот вопрос, но ответы не применимы или достаточно конкретны.
Аргументы Byval и ByRef должны использоваться на основе требований и знаний о том, как они работают не на скорости.
http://www.developer.com/net/vb/article.php/3669066
В ответ на комментарий Слау -
Что потребляет больше ресурсов во время выполнения?
Параметры передаются в стеке. Стек очень быстро, потому что его распределение памяти - это просто шаг указателя, чтобы зарезервировать новый "кадр" или "запись распределения". Большинство параметров .NET не превышают размер машинного регистра так мало, если для передачи параметров используется любое "стек" пространство. Фактически базовые типы и указатели выделяются в стеке. Размер стека в .NET ограничен 1 Мб. Это должно дать вам представление о том, сколько ресурсов потребляется при передаче параметров.
Вы можете найти эту интересную статью:
Улучшение производительности путем размещения стека (управление памятью .NET: часть 2)
Что быстрее? ByVal или ByRef.
В лучшем случае трудно измерить точно и фею - в зависимости от контекста вашего измерения, но в тесте, который я написал, вызывая метод 100 миллионов раз, пришло следующее:
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
Замечание переменной и присвоения в каждом методе -
Можно сделать вывод, что передача ссылочных типов (строк, классов) ByVal сэкономит некоторое время. Вы также можете сказать, что передаваемые типы значений (integer, byte) - ByVal сэкономит некоторое время.
Снова время пренебрежимо мало в великой схеме вещей. Что еще более важно, используя ByVal и ByRef правильно и понимая, что происходит "за кулисами". Алгоритмы, реализованные в ваших подпрограммах, будут в наибольшей степени влиять на время выполнения вашей программы.
Если вы используете очень большой тип значения (например, Guid довольно большой), может быть очень немного быстрее передать параметр по ссылке. В других случаях может быть больше копирования и т.д., Когда вы передаете по ссылке, чем по значению - например, если у вас есть параметр байта, то один байт явно меньше четырех или восьми байтов, которые будет указывать указатель, если вы передал его по ссылке.
На практике вы почти не должны беспокоиться об этом. Создайте наиболее читаемый код, который почти всегда означает передачу параметров по значению вместо ссылки. Я использую ByRef очень редко.
Если вы хотите повысить производительность и подумайте, что ByRef вам поможет, пожалуйста, тщательно проверите его (в вашей конкретной ситуации), прежде чем совершать его.
EDIT: я отмечаю в комментариях к другому (ранее принятому, теперь удаленному) ответу, что существует много недоразумений относительно того, что означает ByRef vs ByVal, когда дело касается типов значений. У меня есть статья о передаче параметров, которая на протяжении многих лет оказалась популярной - она в терминологии С#, но те же понятия применимы к VB.NET.
Это зависит. Если вы передаете объект, он уже передает указатель. Поэтому, если вы передаете ArrayList (например), и ваш метод добавляет somthing в ArrayList, тогда вызывающий код также имеет тот же объект в ArrayList, который был передан, потому что он тот же ArrayList. Единственный раз, когда он не передает указатель, - это когда вы передаете переменную с внутренним типом данных, например int или double, в функцию. В этот момент он создает копию. Однако размер данных этих объектов настолько мал, что это вряд ли имеет значение в любом случае с точки зрения использования памяти или скорости выполнения.
Если вы передаете ссылочный тип, ByRef работает медленнее.
Это связано с тем, что передаваемый объект является указателем на указатель. Любой доступ к полям на объекте требует разыменования дополнительного указателя, для выполнения которого потребуется несколько дополнительных тактовых циклов.
Если вы передаете тип значения, то byref может быть быстрее, если в структуре много членов, поскольку он передает только один указатель, а не копирует значения в стеке. Что касается доступа к членам, byref будет медленнее, потому что ему нужно выполнить дополнительную разметку указателя (sp- > pValueType- > member vs sp- > member).
Большую часть времени в VB вам не придется беспокоиться об этом.
В .NET редко встречаются типы значений с большим количеством членов. Они, как правило, небольшие. В этом случае передача в тип значения не отличается от передачи в несколько аргументов процедуры. Например, если бы у вас был код, который передавался в объекте Point по значению, он был бы таким же, как метод, который принимал значения X и Y в качестве параметров. Видя DoSomething (x как целое число, y как целое число), вероятно, не вызовет первоочередных проблем. На самом деле, вы, вероятно, никогда бы не подумали дважды об этом.
Если вы определяете типы больших значений своим "я", вам следует, вероятно, пересмотреть их в ссылочные типы.
Единственное другое отличие заключается в увеличении числа указателей, требуемых для выполнения кода. Редко, когда вам нужно оптимизировать на этом уровне. В большинстве случаев есть либо алгоритмические проблемы, на которые вы можете обратиться, либо ваше "узкое место" на стороне вашего компьютера связано с IO, например, ожидание базы данных или запись в файл, и в этом случае устранение указателей не поможет вам.
Итак, вместо того, чтобы сосредотачиваться на том, что вы делаете byval или byref быстрее, я бы рекомендовал вам сосредоточиться на том, что дает вам семантику, которая вам нужна. В общем, это хорошая идея использовать byval, если вам не нужен только byref. Это облегчает понимание программы.
Хотя я мало знаю о внутренних компонентах .NET, я расскажу о том, что я знаю о скомпилированных языках. Это не относится к ссылочным типам и может быть не совсем точным в отношении типов значений. Если вы не знаете разницу между типами значений и ссылочными типами, вы не должны это читать. Я предполагаю 32-разрядный x86 (с 32-разрядными указателями).
Приговор:
Гораздо важнее понять, что на самом деле делают ByVal и ByRef для вас, и понимать разницу между значениями и ссылочными типами, чем думать о производительности. Правило номер один: использовать любой метод, более подходящий для вашего кода.
Для больших типов значений (более 64 бит) передайте по ссылке, если нет преимущества для передачи по значению (например, более простой код, "это просто имеет смысл" или согласованность интерфейса).
Для меньших типов значений механизм передачи не имеет большого значения для производительности, и в любом случае трудно предсказать, какой метод будет быстрее, поскольку он зависит от размера объекта, того, как вызывающий и вызываемый используют объект, и даже кэш. Просто делайте то, что имеет смысл для вашего кода.
ByVal
создает копию переменной, тогда как ByRef
передает указатель. Поэтому я бы сказал, что ByVal
медленнее (из-за времени, которое требуется для копирования) и использует больше памяти.
Мое любопытство заключалось в том, чтобы проверять различные типы поведения, связанные с использованием объектов и памяти
Результат кажется демостратом, что 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