أداء ByRef vs ByVal عند تمرير السلاسل
-
26-09-2020 - |
سؤال
قراءة وهو أسرع؟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
المحلول
سلاسل غير صحيح منسوخ قبل أن يتم تمريره.السلاسل هي أنواع مرجعية، على الرغم من أنها تتصرف مثل أنواع القيم إلى حد ما.
يجب عليك استخدام كل ما هو منطقي في سياق متطلباتك.(وإذا كانت متطلباتك شيئًا مثل "يجب الضغط على كل نانو ثانية أخيرة من الأداء على حساب جميع الاعتبارات الأخرى" فمن المحتمل أن يتعين عليك التخلص من ملف التعريف بدلاً من السؤال عن تدفق المكدس!)
من المؤكد تقريبًا أن هذا شيء لا داعي للقلق بشأنه، وأشك في وجود فرق كبير في الأداء على الإطلاق.الموقف الوحيد الذي أستطيع أن أرى فيه أي فرصة للفارق هو عند التمرير كبير أنواع القيمة.
نصائح أخرى
قررت التحقق من ذلك بنفسي للحصول على إجابة "علمية" أكثر.إنهم متشابهون.إذا استخدمت الكود أدناه، فسيكون ByVal أبطأ بنسبة 2٪ تقريبًا من ByRef.ومع ذلك، إذا قمت بتبديلها، بحيث أقوم بتوقيت ByRef قبل ByVal، فإن 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
لفهم سلوك أنواع الفئات، بما في ذلك السلاسل، يجب مراعاة جميع معلمات نوع الفئة والمتغيرات والحقول وعناصر المصفوفة، وما إلى ذلك.كعقد "معرفات الكائنات".لو Foo
هو متغير من النوع string
, ، البيان Foo = 12345.ToString();
سيتم إنشاء معرف كائن جديد (افتراضيًا، معرف الكائن # 197)، وإنشاء كائن جديد من النوع string
بهذا المعرف، الذي يحمل الأحرف الخمسة "12345"
.سيتم بعد ذلك تخزينها Object ID#197
في المتغير Foo
.إذا قام أحد باستدعاء روتين بمعلمة غير مرجعية param
, ، ويمر Foo
إليها إذن param
سيكون عقد متغير محلي Object ID #197
.البيان param += "6";
من شأنه إنشاء كائن جديد (على سبيل المثالمعرف الكائن #521)، من النوع سلسلة، يحمل الأحرف الستة "123456"
وتخزينها Object ID #521
داخل param
.لاحظ أن Foo
لا يزال يحمل Object ID#197
, ، ولا يزال هذا الكائن يحتفظ بالسلسلة المكونة من خمسة أحرف "12345"
.
لو param
قد تم تمريرها ref
, ، ثم البيان param += "6"
سيكون مخزنا Object ID #521
داخل Foo
.لا يزال من غير الممكن أن يتسبب في أي تغيير ملحوظ في الكائن رقم 197، باستثناء ربما جعله مؤهلاً لجمع البيانات المهملة (إذا Foo
كان المرجع الوحيد إلى الكائن رقم 197، فإن الكتابة فوقه تعني أنه لن يكون هناك أي إشارة إلى هذا الكائن في أي مكان في الكون).
لاحظ أنه من السهل عمومًا التفكير في أنواع الفئات غير القابلة للتغيير مثل string
, ، حتى بدون التفكير في معرفات الكائنات، نظرًا لأن الطريقة الوحيدة لتغيير تسلسل الأحرف التي يمثلها متغير سلسلة هي تخزين معرف كائن مختلف هناك.ومع ذلك، يصبح التفكير فيما يتعلق بمعرفات الكائنات أمرًا ضروريًا عند التعامل مع أنواع الفئات القابلة للتغيير.تمرير متغير من نوع الفئة Car
, ، وليس عن طريق المرجع، سيكون معادلاً لنسخ رقم VIN من قصاصة ورق إلى أخرى، وتسليم القصاصة الأخيرة من الورق لبعض عمال المتجر، ومطالبتهم بفعل شيء ما بها.إذا حددت الورقة الأولى في الأصل سيارة حمراء تحمل رقم VIN#15934، فعند انتهاء العمال، قد تحدد الورقة الأولى سيارة زرقاء تحمل رقم VIN#15934، ولكنها ستكون نفس السيارة.لا شيء يستطيع العمال فعله بقصاصة الورق التي حصلوا عليها، ولا أي شيء يمكنهم فعله بالسيارة، من شأنه أن يغير السيارة التي أشارت إليها الورقة الأولى.من ناحية أخرى، فإن تمرير المعلمة حسب المرجع سيكون أشبه بقطعة من الورق مكتوب عليها رقم VIN لعمال المتجر، واستعادة الورقة منهم عند الانتهاء.إذا تمكن العمال من شطب رقم VIN وكتابة رقم آخر، فعند إعادة قصاصة الورق قد يشير ذلك إلى نفس السيارة أو سيارة مختلفة؛إذا كانت تشير إلى سيارة مختلفة، فقد تكون السيارة التي أشارت إليها في الأصل قد تم تعديلها أو لا، والسيارة التي تشير إليها الورقة في النهاية قد تحمل أو لا تحمل أي تشابه مع السيارة الأصلية.