Frage

In VB.NET, die schneller ist für Methodenargumente zu verwenden, ByVal oder ByRef?

Auch die mehr Ressourcen zur Laufzeit (RAM) verbraucht?


Ich las href="https://stackoverflow.com/questions/290189/best-practice-byref-or-byval-in-net">, aber die Antworten sind nicht anwendbar oder spezifisch genug.

War es hilfreich?

Lösung

ByVal und ByRef Argumente sollten basierend auf den Anforderungen und das Wissen verwendet werden, wie sie funktionieren nicht auf der Geschwindigkeit.

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

Als Reaktion auf einen Kommentar von Slough -

Welche mehr Ressourcen zur Laufzeit verbraucht?

Die Parameter werden auf dem Stack übergeben. Der Stapel ist sehr schnell, weil seine Speicherzuweisung ist einfach ein Zeiger Schritt einen neuen „Rahmen“ oder zu reservieren „allocation Rekord.“ Die meisten .NET-Parameter nicht überschreiten die Größe einer Maschine so wenig registrieren, wenn ein „Stack“ Raum verwendet wird, um Parameter zu übergeben. In der Tat sind Grundtypen und Hinweise sowohl auf dem Stack zugeordnet. Die Stapelgröße in .NET ist auf 1 MB beschränkt. Dies sollten Sie eine Vorstellung davon, wie wenige Ressourcen durch Parameterübergabe verbraucht werden.

Sie können diese Serie von Artikeln interessant finden:

Verbesserung der Leistung durch Stapel Allocation (.NET Memory Management: Part 2)

Was ist schneller? ByVal oder ByRef.

Es ist schwierig, im besten Fall genau zu messen und Fee - je nach Kontext Ihrer Messung, sondern eine Benchmark ich einer Methode 100 Millionen Mal kam mit dem folgenden Aufruf schrieb:

  • Referenz Typ - Bestanden ByRef: 420 ms
  • Referenz Typ - Bestanden ByVal: 382 ms
  • Wert Typ - Bestanden ByRef: 421 ms
  • Wert Typ - Bestanden ByVal: 416 ms
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

die Variable und Zuordnung in jedem Verfahren kommentiert out -

  • Referenz Typ - Bestanden ByRef: 389 ms
  • Referenz Typ - Bestanden ByVal: 349 ms
  • Wert Typ - Bestanden ByRef: 416 ms
  • Wert Typ - Bestanden ByVal: 385 ms

könnte man schließen, dass vorbei Referenztypen (Strings, Klassen) ByVal wird einige Zeit sparen. Man könnte auch sagen, dass Durchgangswerttypen (Integer, Byte) -. ByVal wird einige Zeit speichern

Auch hier ist die Zeit in dem großen Plan der Dinge zu vernachlässigen. Was noch wichtiger ist, mit ByVal und ByRef richtig und zu verstehen, was los ist „hinter den Kulissen.“ Die Algorithmen in Ihre Routinen implementiert werden die meisten sicherlich Auswirkungen auf die Laufzeit des Programms ein vielfaches.

Andere Tipps

Wenn Sie einen sehr großen Wert Typen verwenden (Guid ist ziemlich groß, zum Beispiel) kann es sehr leicht sein, schneller einen Parameter als Verweis zu übergeben. In anderen Fällen kann es mehr Kopieren etc, wenn Sie über einen Verweis als von Wert - zum Beispiel, wenn Sie ein Byte-Parameter haben, dann ein Byte deutlich weniger als die vier oder acht Bytes ist dass der Zeiger würde, wenn Sie es als Verweis übergeben.

In der Praxis sollten Sie so gut wie nie kümmern. Schreiben Sie die lesbar Code möglich, die fast immer bedeutet, von Wert Parameter übergeben statt Referenz. Ich benutze ByRef sehr selten.

Wenn Sie möchten, die Leistung verbessern und denken, dass ByRef Ihnen helfen, Sie Benchmark vorsichtig (in Ihre genaue Situation), bevor Sie handeln.

EDIT: Ich stelle fest, in den Kommentaren zu einem anderen (bisher angenommen, nun gelöscht) antworten, dass eine große Menge von Missverständnissen es geht darum, was BYREF vs ByVal bedeutet, wenn es um Wertetypen kommt. Ich habe eine Artikel über Parameter geben, die über die Jahre populär erwiesen hat - es ist in C # Terminologie, aber die gleichen Konzepte gelten für VB.NET.

Es hängt davon ab. Wenn Sie ein Objekt vorbei, wird es vorbei schon einen Zeiger. Deshalb, wenn Sie in einer Arraylist (zum Beispiel) übergeben und Ihre Methode fügt somthing die Arraylist, dann auch der Angerufene Code das gleiche Objekt hat in es ist Arraylist, dass übergeben wurde, weil es die gleiche Arraylist ist. Das einzige Mal, dass es keinen Zeiger nicht besteht, ist, wenn man eine Variable mit einer intrinsischen Datentyp passieren, wie ein int, oder eine Doppel, in die Funktion. An diesem Punkt, erstellt es eine Kopie. die Datengröße dieser Objekte ist jedoch so klein, dass es kaum einen Unterschied oder so, in Bezug auf die Speichernutzung oder Geschwindigkeit der Ausführung machen würde.

Wenn Sie in einem Referenztyp sind vorbei, ByRef ist langsamer.

Das liegt daran, was in übergeben wird ein Zeiger auf einen Zeiger. Jeder Zugriff auf Felder auf dem Objekt erfordert dereferencing einen zusätzlichen Zeiger, der ein paar zusätzlichen Taktzyklen dauern wird abgeschlossen.

Wenn Sie einen Werttyp sind vorbei, dann kann byref schneller sein, wenn die Struktur viele Mitglieder hat, weil es nur einen einzigen Zeiger geht, anstatt das Kopieren der Werte auf dem Stapel. In Bezug auf den Zugriff auf Mitglieder wird byref langsamer sein, weil es eine zusätzliche Pointer-Dereference (sp-> pValueType-> Mitglied vs sp-> Mitglied) tun muss.

Die meiste Zeit in VB Sie sollten nicht darüber Sorgen zu machen.

In .NET ist es selten, Werttypen mit einer großen Anzahl von Mitgliedern. Sie sind in der Regel klein. In diesem Fall wird in einem Werttyp vorbei ist nicht anders als in mehreren Argumenten auf eine Prozedur übergeben. wenn Sie Code hatte zum Beispiel, die von Wert in einem Point-Objekt übergeben, dann ist es perf das gleiche wie ein Verfahren sein würde, die X- und Y-Werte als Parameter hat. Sehen DoSomething (x als Integer, y als integer) würde wahrscheinlich nicht perf Bedenken verursachen. In der Tat, würden Sie wahrscheinlich denken, nie zweimal darüber.

Wenn Sie große Werttypen Sie sich selbst definieren, dann sollten Sie vielleicht überdenken sie in Referenztypen drehen.

Der einzige andere Unterschied ist die Zunahme der Zahl der Zeiger Indirekt erforderlich, um den Code auszuführen. Es ist selten, dass man jemals auf dieser Ebene optimieren müssen. Die meiste Zeit gibt es entweder algorithmische Probleme, die Sie ansprechen können, oder Ihre perf Engpass IO bezogen, wie für eine Datenbank warten oder in eine Datei zu schreiben, wobei in diesem Fall die Beseitigung Zeiger Indirekt wird nicht viel helfen.

Also, statt auf der Fokussierung wheter byval oder byref schneller ist, würde ich empfehlen, dass Sie wirklich konzentrieren sollte, was gibt Ihnen die Semantik, die Sie benötigen. Im Allgemeinen ist es gute Idee byval zu verwenden, wenn Sie speziell byref benötigen. Es macht das Programm viel einfacher zu verstehen.

Während ich nicht viel über die Interna von .NET wissen, werde ich diskutieren, was ich über kompilierten Sprachen kennen. Diese gilt nicht Typen Referenz und nicht vollständig über Werttypen genau. Wenn Sie nicht den Unterschied zwischen Werttypen und Referenztypen kennen, sollten Sie das nicht lesen. Ich werde 32-Bit-x86-nehmen (mit 32-Bit-Zeiger).

  • Passing Werte kleiner als 32 Bits immer noch verwendet ein 32-Bit-Objekt auf dem Stapel. Ein Teil dieses Objekt wird „ungenutzt“ oder „padding“. nicht solche Werte Passing nicht weniger Speicher als Übergang 32-Bit-Werte.
  • Passing Werte größer als 32 Bits mehr Stapelspeicher als ein Zeiger verwenden, und wahrscheinlich mehr Kopierzeit.
  • Wenn ein Objekt von Wert übergeben wird, kann die Angerufene das Objekt aus dem Stapel holen. Wenn ein Objekt als Referenz übergeben wird, muss der Angerufene zuerst die Adresse des Objekts holen aus dem Stapel, und dann wird der Wert des Objekts fetch von anderswo. Mit dem Wert bedeutet eine weniger holen, nicht wahr? Na ja, eigentlich der Abruf Bedürfnisse vom Anrufer gemacht werden -. Aber der Anrufer bereits hatte aus verschiedenen Gründen zu holen, in dem Fall einer Abruf wird gespeichert
  • Offensichtlich werden alle Änderungen an einem Nebenreferenzwert zurück zu RAM gespeichert werden müssen, während ein Nebenwert Parameter verworfen werden kann.
  • Es ist besser, nach Wert zu übergeben, als nur durch Verweis übergeben Sie die Parameter in einer lokale Variable kopieren und es nicht wieder berühren.

Das Urteil:

Es ist viel wichtiger, zu verstehen, was ByVal und ByRef tatsächlich für Sie tun, und verstehen den Unterschied zwischen Wert und Referenztypen, als über die Leistung zu denken. Die Nummer eins der Regel ist auf Verwendung der gewünschten Methode besser geeignet, um Ihren Code ist .

Für große Werttypen (mehr als 64 Bits), durch Verweis übergeben, es sei denn es ist ein Vorteil von Wert vorbei (wie einfacher Code, „es macht einfach Sinn“, oder Schnittstelle Konsistenz).

Für kleinere Werttypen, wird der Durchgangsmechanismus nicht viel Unterschied, um die Leistung zu machen, und trotzdem ist es schwer, welche Methode wird schneller sein, vorherzusagen, da sie von der Objektgröße abhängig ist, wie der Anrufer und Angerufenen das Objekt verwenden, und auch Cache-Überlegungen. Genau das tun, was auch immer Sinn für Ihren Code macht.

ByVal erstellt eine Kopie der Variablen, während ByRef einen Zeiger durchläuft. Ich würde also sagen, dass ByVal langsamer ist (aufgrund Zeit in Anspruch nimmt, es zu kopieren) und mehr Speicher.

war meine Neugier, die verschiedenen Verhaltensweisen zu überprüfen Objekt und Speicher Verwendungen je

Das Ergebnis scheint, dass demostrate ByVal immer gewinnt, hängt die Ressource, wenn collect Speicher oder weniger (4.5.1 nur)

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
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top