source

어느 것이 더 빠릅니까?Val 또는 ByRef 기준?

manysource 2023. 5. 25. 22:09

어느 것이 더 빠릅니까?Val 또는 ByRef 기준?

인수에 이 더 NET에서는 VB를 합니다.NET에서는ByVal또는ByRef?

또한 런타임(RAM)에 더 많은 리소스를 사용하는 것은 무엇입니까?


는 이 질문을 통해 읽었지만, 답이 충분히 적용 가능하거나 구체적이지 않습니다.

Byval 및 ByRef 인수는 속도에서 작동하지 않는 방법에 대한 요구 사항과 지식을 기반으로 사용해야 합니다.

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

슬로우의 논평에 대한 답변 -

런타임에 리소스를 더 많이 사용하는 것은 무엇입니까?

매개 변수가 스택에 전달됩니다.스택은 메모리 할당이 새로운 "프레임" 또는 "할당 레코드"를 예약하기 위한 포인터 증분에 불과하기 때문에 매우 빠릅니다.대부분의 .NET 매개 변수는 매개 변수를 전달하는 데 "스택" 공간이 사용되는 경우 시스템 레지스터의 크기를 초과하지 않습니다.사실 기본 유형과 포인터는 모두 스택에 할당됩니다..NET의 스택 크기는 1MB로 제한됩니다.이렇게 하면 매개 변수 전달에 의해 사용되는 리소스가 얼마나 적은지 알 수 있습니다.

다음과 같은 일련의 기사가 흥미로울 수 있습니다.

스택 할당을 통한 성능 향상(.NET 메모리 관리: Part 2)

어느 것이 더 빠릅니까?기준 또는 기준별.

측정의 맥락에 따라 정확하고 공정하게 측정하는 것은 기껏해야 어렵지만, 내가 1억 번 방법을 호출하여 작성한 벤치마크는 다음과 같습니다.

  • 기준 유형 - 기준 통과: 420ms
  • 기준 유형 - Val에 의해 전달됨: 382ms
  • 값 유형 - 기준에 의해 전달됨: 421ms
  • 값 유형 - Val에 의해 전달됨: 416ms
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

각 방법의 변수와 과제에 대한 주석 달기 -

  • 참조 유형 - 전달된 참조: 389ms
  • 기준 유형 - 전달된 Val: 349ms
  • 값 유형 - 기준에 의해 전달됨: 416ms
  • 값 유형 - Val에 의해 전달됨: 385ms

기준 유형(문자열, 클래스) ByVal을 통과하면 시간이 절약된다는 결론을 내릴 수 있습니다.값 유형(정수, 바이트)을 전달하면 시간이 절약된다고 말할 수도 있습니다.

다시 말하지만, 그 시간은 사물의 웅장한 계획에서 무시할 수 있습니다.더 중요한 것은 ByVal과 ByRef를 적절히 사용하고 "막후에서" 무슨 일이 일어나고 있는지 이해하는 것입니다.루틴에 구현된 알고리즘은 프로그램의 런타임에 몇 배 더 확실히 영향을 미칠 것입니다.

매우 큰 값 유형(예: Guid가 상당히 큼)을 사용하는 경우에는 기준으로 매개 변수를 전달하는 것이 매우 빠를 수 있습니다.다른 경우에는 값보다 참조로 전달할 때 복사 등이 더 많을 수 있습니다. 예를 들어 바이트 매개 변수가 있는 경우 1바이트는 포인터가 참조로 전달할 때 걸리는 4바이트 또는 8바이트보다 분명히 작습니다.

실제로, 여러분은 이것에 대해 거의 걱정하지 말아야 합니다.가능한 가장 읽기 쉬운 코드를 작성합니다. 이는 거의 항상 참조 대신 값으로 매개 변수를 전달하는 것을 의미합니다.저는 바이레프를 거의 사용하지 않습니다.

성능을 개선하고 ByRef가 도움이 될 것이라고 생각하는 경우, 정확한 상황에서 ByRef를 사용하기 전에 신중하게 벤치마킹하십시오.

편집: 다른 답변(이전에 수락되었거나 현재 삭제됨)에 대한 의견에서 ByRef 대 ByVal이 의미하는 가치 유형에 대해 상당한 오해가 있음을 지적합니다.수년간 널리 사용되어 온 매개 변수 전달에 대한 기사가 있습니다. 이 기사는 C# 용어이지만 VB.NET에도 동일한 개념이 적용됩니다.

사정에 따라 다르겠지.개체를 전달하는 경우 이미 포인터를 전달하고 있습니다.그렇기 때문에 (예를 들어) ArrayList를 전달하고 메서드가 ArrayList에 무언가를 추가하면 호출 코드도 전달된 ArrayList에 동일한 개체를 포함합니다. 왜냐하면 동일한 ArrayList이기 때문입니다.포인터를 통과하지 않는 유일한 시간은 함수에 int나 double과 같은 고유한 데이터 유형을 가진 변수를 전달할 때입니다.이 시점에서 복사본이 생성됩니다.그러나 이러한 개체의 데이터 크기는 너무 작아서 메모리 사용량이나 실행 속도 측면에서 어느 쪽이든 거의 차이가 없습니다.

참조 유형을 전달하는 경우 기준이 더 느립니다.

이것은 전달되는 것이 포인터에 대한 포인터이기 때문입니다.개체의 필드에 액세스하려면 추가 포인터를 다시 참조해야 합니다. 이 포인터는 완료하는 데 몇 번의 추가 클럭 주기가 필요합니다.

값 유형을 전달하는 경우 구조가 스택에 값을 복사하지 않고 단일 포인터만 전달하기 때문에 구조에 멤버가 많으면 ref가 더 빠를 수 있습니다.멤버에 접근하는 측면에서 Byref는 추가 포인터 참조 해제(sp->pValueType->member vs sp->member)를 수행해야 하기 때문에 속도가 느려집니다.

VB에서는 대부분 이 문제에 대해 걱정할 필요가 없습니다.

.NET에서는 멤버 수가 많은 값 유형을 갖는 경우가 거의 없습니다.그들은 보통 작습니다.이 경우 값 형식을 전달하는 것은 절차에 여러 인수를 전달하는 것과 다를 바 없습니다.예를 들어, 값별로 Point 객체에 전달된 코드가 있는 경우 X 및 Y 값을 매개 변수로 사용하는 방법과 성능이 같습니다.DoSomething(x는 정수, y는 정수)을 보면 성능 문제가 발생하지 않을 수 있습니다.사실, 여러분은 아마도 그것에 대해 두 번 생각하지 않을 것입니다.

큰 값 유형을 직접 정의하는 경우에는 이러한 유형을 참조 유형으로 전환하는 것을 다시 고려해야 합니다.

유일한 차이점은 코드를 실행하는 데 필요한 포인터의 수가 증가했다는 것입니다.이러한 수준에서 최적화가 필요한 경우는 거의 없습니다.대부분의 경우 해결할 수 있는 알고리즘 문제가 있거나 데이터베이스 대기 또는 파일 쓰기와 같은 성능 병목 현상이 IO와 관련되어 있습니다. 이 경우 지침에 대한 포인터 제거는 큰 도움이 되지 않습니다.

그래서, 저는 여러분이 발이나 바이레프가 더 빠른지에 초점을 맞추는 대신, 여러분에게 필요한 의미론을 제공하는 것에 초점을 맞추는 것을 추천합니다.일반적으로 바이레프가 특별히 필요한 경우가 아니라면 val로 사용하는 것이 좋습니다.그것은 프로그램을 훨씬 더 이해하기 쉽게 만듭니다.

.NET 내부에 대해서는 잘 모르지만 컴파일된 언어에 대해서는 제가 알고 있는 것에 대해서는 논의하겠습니다.이는 참조 유형에는 적용되지 않으며 값 유형에 대해 완전히 정확하지 않을 수 있습니다.값 유형과 참조 유형의 차이를 모르면 이 문서를 읽지 마십시오.32비트 x86(32비트 포인터 포함)을 가정하겠습니다.

  • 32비트보다 작은 값을 전달하는 경우에도 스택에서 32비트 개체를 사용합니다.이 개체의 일부는 "사용되지 않음" 또는 "패딩"이 됩니다.이러한 값을 전달하는 것은 32비트 값을 전달하는 것보다 더 적은 메모리를 사용하지 않습니다.
  • 32비트보다 큰 값을 전달하면 포인터보다 스택 공간이 더 많이 사용되고 복사 시간도 더 많이 사용됩니다.
  • 개체가 값으로 전달되면 호출자는 스택에서 개체를 가져올 수 있습니다.개체가 참조로 전달되는 경우, 호출자는 먼저 스택에서 개체의 주소를 가져온 다음 다른 곳에서 개체의 값을 가져와야 합니다.가치는 한 번만 더 얻는 것을 의미합니다, 그렇죠?실제로는 호출자가 페치를 수행해야 하지만, 다른 이유로 이미 페치를 수행해야 했을 수 있으며, 이 경우 페치가 저장됩니다.
  • 기준 값에 대한 변경 사항은 RAM에 다시 저장해야 하지만 기준 값 매개 변수는 삭제할 수 있습니다.
  • 매개 변수를 로컬 변수에 복사하고 다시는 건드리지 않기 위해 참조로만 전달하는 것보다 값으로 전달하는 것이 좋습니다.

판결문:

성능에 대해 생각하는 것보다 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

언급URL : https://stackoverflow.com/questions/408101/which-is-faster-byval-or-byref