4

どちらが速いですか?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
4

3 に答える 3

10

文字列は渡される前にコピーされません。文字列は、値型のように動作しますが、参照型です。

要件のコンテキストで最も意味のあるものを使用する必要があります。(そして、あなたの要件が「他のすべての考慮事項を犠牲にして、パフォーマンスの最後のナノ秒ごとに絞り込まなければならない」のようなものである場合は、スタックオーバーフローを要求するのではなく、おそらくプロファイラーをクラックする必要があります!)

これはほぼ間違いなく心配する必要はありません。パフォーマンスに大きな違いがあるかどうかは疑問です。違いの可能性が見られる唯一の状況は、大きな値型を渡すときです。

于 2010-07-22T11:07:39.103 に答える
2

より「科学的な」答えを得るために、これを自分で確認することにしました。それらは同じです。以下のコードを使用すると、ByVal は ByRef より約 2% 遅くなります。ただし、ByVal の前に ByRef のタイミングをとるようにそれらを入れ替えると、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
于 2012-07-20T10:13:54.353 に答える
0

文字列を含むクラス型の動作を理解するには、すべてのクラス型パラメーター、変数、フィールド、配列要素などを「オブジェクト ID」を保持しているものと見なします。Fooが type の変数である場合string、ステートメントFoo = 12345.ToString();は新しいオブジェクト ID (仮想的にはオブジェクト ID#197) を作成し、stringその ID を持つ type の新しいオブジェクトを作成し、5 文字を保持し"12345"ます。Object ID#197その後、変数に格納されますFoo。ref 以外のパラメータを指定してルーチンを呼び出し、それにparam渡すと、 はを保持するローカル変数になります。このステートメントは、string 型の新しいオブジェクト (例: Object ID #521) を作成し、6 文字を保持してに格納します。ご了承くださいFooparamObject ID #197param += "6";"123456"Object ID #521paramFooを保持しObject ID#197、そのオブジェクトは引き続き 5 文字の文字列 を保持します"12345"

paramが渡された場合ref、ステートメントparam += "6"は に格納さObject ID #521Fooます。おそらくガベージ コレクションの対象にすることを除いて、オブジェクト #197 への目に見える変更は発生しませんでした (Fooオブジェクト #197 への唯一の参照であった場合、それを上書きすると、そのオブジェクトへの参照が存在しなくなることを意味します)。宇宙のどこにでもある)。

オブジェクト ID の観点から考えなくても、のような不変クラス型について推論するのは一般に非常に簡単であることに注意してくださいstring。文字列変数によって表される文字のシーケンスを変更する唯一の方法は、そこに別のオブジェクト ID を格納することだからです。ただし、変更可能なクラス型を扱う場合は、オブジェクト ID の観点から考えることが不可欠になります。クラス型の変数を渡すCar、参照ではなく、VINをある紙片から別の紙片にコピーし、後者の紙片を一部の店員に渡して、それを使って何かをするように頼むのと同じです. 最初の論文で最初に VIN#15934 の赤い車が識別された場合、ワーカーの作業が完了すると、最初の論文で VIN#15934 の青い車が識別される可能性がありますが、それは同じ車です。労働者が与えられた紙片でできることは何もなく、車でできることでも、最初の紙が言及した車を変えることはできませんでした. 一方、パラメーターを参照渡しすることは、作業員が VIN が書かれた紙を受け取り、作業が終わったときに紙を取り戻すようなものです。従業員が VIN を消して別の VIN を書くことができれば、その後、彼らが紙片を返したとき、それは同じ車または別の車に言及している可能性があります。それが別の車に言及している場合、最初に言及された車は変更されている場合とされていない場合があります。

于 2012-07-20T15:40:01.047 に答える