2009-06-08 4 views
9

Bei der Überprüfung des Codes stieß ich auf eine Reihe neuer Private Shared-Variablen (vom Typ Hashtables (Of String), initialisiert in der Deklaration), die zu einer partiellen Klasse für eine sehr große (DataContext-abgeleitete) Klasse hinzugefügt wurden. Dies erscheint mir in einem Sinn sinnvoll, weil sie sich niemals ändern und diese geteilten Variablen sicherstellen, dass sie nicht jedes Mal neu initialisiert werden, wenn eine Funktion aufgerufen wird. Diese Variablen sind nur innerhalb des Bereichs einer Funktion in der Klasse verwendet, und ich fürchte, der private Namespace dieser DataContext-abgeleiteten Klasse wird ziemlich verschmutzt, und diese Dinge auf einem so hohen Niveau ausgesetzt sein könnte verwirrend für andere, die den Code in der Zukunft lesen. Würde es negative Auswirkungen auf die Leistung haben, diese lokalen Variablen in der Funktion zu verwenden, in der sie verwendet werden, oder gibt es einen besseren Weg, damit umzugehen? Im Grunde verwenden wir diese 3 Hashtabellen, um zu bestimmen, ob sich irgendetwas innerhalb bestimmter Teilmengen von Eigenschaften geändert hat (mit GetModifiedMembers und dann mit der Overlaps-Funktion des Hashsets, um festzustellen, ob eines der modifizierten Mitglieder den Mitgliedern entspricht, die uns interessieren).Private Shared-Variablen im Vergleich zu lokalen Variablen/Namespace Pollution vs Performance?

Edit: Ich gab nach und nahm mir die Zeit, um mein eigenes Testprogramm zu schreiben, das bestätigte, dass es Kosten für die Verwendung von lokalen Variablen gibt (was ich generell für alle Fälle anwende). Ich bezweifle, dass es einen Fall gibt Variable langsamer sein würde, es sei denn, die gemeinsame Variable einige zusätzliche Logik erfordert, so richtig zu machen):

Sub Main() 
    Dim st As New Stopwatch() 
    Dim specialCount As Integer = 0 
    Dim r As New Random() 
    Dim params As Integer() 
    ReDim params(0 To 9) 
    st.Start() 
    For i As Integer = 1 To 100000 
    For j As Integer = 0 To 9 
     params(j) = r.Next(100) 
    Next 
    If IsSpecialShare(params) Then specialCount += 1 
    Next 
    st.Stop() 

    Console.WriteLine("Shared: " & specialCount) 
    Console.WriteLine(st.Elapsed.ToString()) 

    st.Reset() 
    specialCount = 0 

    st.Start() 
    For i As Integer = 1 To 100000 
    For j As Integer = 0 To 9 
     params(j) = r.Next(100) 
    Next 
    If IsSpecialLocal(params) Then specialCount += 1 
    Next 
    st.Stop() 

    Console.WriteLine("Local: " & specialCount) 
    Console.WriteLine(st.Elapsed.ToString()) 

End Sub 

Dim specialListShared As New HashSet(Of Integer)(New Integer() {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41}) 

Private Function IsSpecialLocal(ByVal paramList As IEnumerable(Of Integer)) As Boolean 
    Dim specialListLocal As New HashSet(Of Integer)(New Integer() {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41}) 
    Return specialListLocal.Overlaps(paramList) 
End Function 

Private Function IsSpecialShare(ByVal paramList As IEnumerable(Of Integer)) As Boolean 
    Return specialListShared.Overlaps(paramList) 
End Function 

Beispielausgabe:

Shared: 75232 
00:00:00.0408223 
Local: 75018 
00:00:00.1344628 

so in diesem speziellen Fall die lokale Variable kostet etwa 200% . Aber in den meisten Fällen (einschließlich meiner eigenen) ist die Zeit im Vergleich zur Gesamtaufgabe wahrscheinlich vernachlässigbar. Ich denke also, die Frage wird nun, wie fühlen sich die Menschen im Allgemeinen dazu, die Wartbarkeit des Codes auf Kosten von vernachlässigbaren, aber bekannten Leistungseinbußen zu verbessern?

Antwort

6

Ich würde sagen, dass Sie feststellen müssen, ob diese statischen Variablen wirklich zum Namespace, Klasse oder Funktion gehören. Wenn sie wirklich spezifisch für die Funktion sind, dann würde ich sie in die Funktion einfügen.

Wenn Sie Variablen benötigen, die den Status beibehalten, auch wenn die Funktion den Gültigkeitsbereich verlässt, können Sie sie als Static deklarieren. Das schließt das Problem aus, diese Variablen im Klassenbereich zu haben.

Unterschied zwischen Shared Klassenvariable, statischer Funktion variabel, und lokale Funktionsvariablen:

Geteilt: Es wird nur eine Kopie der Variablen unter allen Klasseninstanzen sein.

Statisch: Es wird eine Kopie der Variablen pro Instanz Ihrer Klasse geben.

Lokal: Eine Kopie der Variablen wird jedes Mal erstellt, wenn die Funktion aufgerufen wird (aber freigegeben, sobald die Funktion den Gültigkeitsbereich verlässt).

Verwenden Sie den, der in Ihrer Situation sinnvoll ist.

+0

Ich glaube nicht, ich bin besorgt über tatsächliche messbare Leistung hier, da der Unterschied wahrscheinlich nicht nachweisbar klein wäre. Und es gibt leistungsorientierte Richtlinien da draußen, unabhängig von der Notwendigkeit, einzelne Fälle zu profilieren. Genau darum geht es mir hier. Zum Beispiel sollten Sie in der Regel stark typisierte Variablen anstelle von Objektreferenzen verwenden, um mit Werttypen umzugehen, wo dies aufgrund der Kosten für das Boxing und das Un-Boxing möglich ist. Meine ähnliche Frage lautet, ob bei der Verwendung lokaler Variablen statt gemeinsamer Variablen erhebliche Kosten zu berücksichtigen sind. Nutzen/Kosten? – BlueMonkMN

+0

Eigentlich ist es eine Konstante, aber (obwohl VB.NET lokale Konstanten erlaubt) ist es nicht möglich, eine Konstante mit dieser Art von Wert zu deklarieren, also müssen wir eine Variable deklarieren. Und dann stoßen wir auf eine ähnliche Frage: Sind die Kosten des Overheads, die zusätzlichen Instanzen zu haben, den Vorteil, den Namensraum der Klasse zu entlasten? Es ist wirklich eine Konstante, die nur auf diese spezifische Funktion anwendbar ist. Es ist nur eine Liste von Eigenschaftsnamen für Eigenschaften, deren Werte innerhalb dieser Funktion behandelt werden. – BlueMonkMN

+0

Dann würde ich es als statische lokale Variable deklarieren. Der Overhead ist wahrscheinlich sehr klein, daher lohnt es sich, den Namensraum der Klasse zu entlasten, es sei denn, es gibt Millionen von Objekten dieses Typs, die erstellt werden. (1 Million Objekte = 1 Million Kopien Ihrer statischen Variablen) –

0

Wenn Sie "shared" sagen - ist das VB-sprechen für static? Wenn ja, beachten Sie, dass Sie sich in einer gewissen Threading-Gefahr befinden könnten, wenn Sie nicht vorsichtig sind ... und angesichts der Beschreibung klingt es so, als ob diese Daten veränderbar sein könnten. Könnte ... "interessant" sein, wenn Sie mehrere Instanzen/Threads haben.

Vielleicht bin ich übermäßig paranoid - hart, ohne illustrativ Code zu erklären ...

Instanz Felder (statt shared/statische Felder) würde meine Standardannahme - aber wieder, ohne Zusammenhang kann ich nicht sei 100% sicher.

+0

Ja, VB.Net Shared = C# Statisch – Pondidum

+3

oder == soll ich sagen? – Pondidum

+0

Sie sollten sich nicht ändern. Siehe meinen Kommentar "Das erscheint mir in einem Sinn sinnvoll, weil sie sich nie ändern". – BlueMonkMN

0

Ich habe fast vergessen, dass VB.NET statische lokale Variablen unterstützt. Der folgende Test zeigt an, dass ich die Leistung bekommen kann genauso gut durch eine statische lokale Variable:

Sub Main() 
    Dim st As New Stopwatch() 
    Dim specialCount As Integer = 0 
    Dim r As New Random() 
    Dim params As Integer() 
    ReDim params(0 To 9) 
    st.Start() 
    For i As Integer = 1 To 100000 
    For j As Integer = 0 To 9 
     params(j) = r.Next(100) 
    Next 
    If IsSpecialShare(params) Then specialCount += 1 
    Next 
    st.Stop() 

    Console.WriteLine("Shared: " & specialCount) 
    Console.WriteLine(st.Elapsed.ToString()) 

    st.Reset() 
    specialCount = 0 

    st.Start() 
    For i As Integer = 1 To 100000 
    For j As Integer = 0 To 9 
     params(j) = r.Next(100) 
    Next 
    If IsSpecialLocal(params) Then specialCount += 1 
    Next 
    st.Stop() 

    Console.WriteLine("Local: " & specialCount) 
    Console.WriteLine(st.Elapsed.ToString()) 

    st.Reset() 
    specialCount = 0 

    st.Start() 
    For i As Integer = 1 To 100000 
    For j As Integer = 0 To 9 
     params(j) = r.Next(100) 
    Next 
    If IsSpecialStatic(params) Then specialCount += 1 
    Next 
    st.Stop() 

    Console.WriteLine("Static: " & specialCount) 
    Console.WriteLine(st.Elapsed.ToString()) 

End Sub 

Dim specialListShared As New HashSet(Of Integer)(New Integer() {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41}) 

Private Function IsSpecialLocal(ByVal paramList As IEnumerable(Of Integer)) As Boolean 
    Dim specialListLocal As New HashSet(Of Integer)(New Integer() {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41}) 
    Return specialListLocal.Overlaps(paramList) 
End Function 

Private Function IsSpecialShare(ByVal paramList As IEnumerable(Of Integer)) As Boolean 
    Return specialListShared.Overlaps(paramList) 
End Function 

Private Function IsSpecialStatic(ByVal paramList As IEnumerable(Of Integer)) As Boolean 
    Static specialListLocal As New HashSet(Of Integer)(New Integer() {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41}) 
    Return specialListLocal.Overlaps(paramList) 
End Function 

Beispielausgabe:

Shared: 74836 
00:00:00.0498081 
Local: 75205 
00:00:00.1317149 
Static: 74862 
00:00:00.0469154 

BTW, habe ich immer gefragt, ob C# statische lokale Variablen unterstützt, und wenn nicht, warum nicht? Es gibt ein paar nervige fehlende Features in C#, die VB.NET unterstützt.

+0

Das ist nicht gut. Statische Variablen von nicht gemeinsamen Funktionen weisen Speicher für jede Instanz zu, was (in unserer Situation) die schlechtesten Kosten von allen ist. Ich nehme an, wir könnten vielleicht eine andere gemeinsame Funktion erstellen, die die Arbeit mit den statischen Variablen erledigt, aber diese Funktion wäre immer noch "Namensraumverschmutzung". Ich denke, wir müssen uns vorerst an das Klassenfeld halten. – BlueMonkMN