StructPerformance: Unterschied zwischen den Versionen

Aus Das Sopra Wiki
Florian (Diskussion | Beiträge)
Keine Bearbeitungszusammenfassung
Florian (Diskussion | Beiträge)
Keine Bearbeitungszusammenfassung
Zeile 5: Zeile 5:
== Call by Value ==
== Call by Value ==


Bei C# geschehen Parameterübergaben bei Funktionsaufrufen (genauso wie bei Java) implizit immer in Form von "Call by Value". Das heisst dass übergebene Variablen für die Verwendung in Methoden kopiert werden.
Bei C# geschehen Parameterübergaben bei Funktionsaufrufen (genauso wie bei Java) implizit immer in Form von "call by value". Das heisst dass übergebene Variablen für die Verwendung in Methoden kopiert werden.


Hier ist ein Codebeispiel dazu:
Hier ist ein Codebeispiel dazu:
Zeile 28: Zeile 28:
     System.Console.WriteLine(test.number);  // gibt 7 aus
     System.Console.WriteLine(test.number);  // gibt 7 aus
     ChangeNumber2(test);
     ChangeNumber2(test);
     System.Console.WriteLine(test.number);  // gibt 3 aus
     System.Console.WriteLine(test.number);  // gibt 4 aus
   }
   }


Zeile 37: Zeile 37:
   public void ChangeNumber2(Test test)
   public void ChangeNumber2(Test test)
   {
   {
     test.number = 3;
     test.number = 4;
   }
   }
}
}
Zeile 46: Zeile 46:
Die Methode ChangeNumber2 greift dagegen über die kopierte Referenz auf die selbe Klasseninstanz zurück, auf die die ursprüngliche Referenz ebenfalls verweist. Daher wird hier der Zahlenwert geändert und anschließend auch entsprechend ausgegeben.
Die Methode ChangeNumber2 greift dagegen über die kopierte Referenz auf die selbe Klasseninstanz zurück, auf die die ursprüngliche Referenz ebenfalls verweist. Daher wird hier der Zahlenwert geändert und anschließend auch entsprechend ausgegeben.


Das selbe Prinzip gilt ähnlich auch für [[CSharp#Structs|Structs]]. Da Structs allerdings [[CSharp#Datentypen|value types]] sind, wird beim Übergeben einer Struct als Parameter nicht nur eine Referenz, sondern der komplette Inhalt der Struct kopiert! Dies kann je nach Inhalt der Struct (z.B. 16 float Werte bei einer Matrix-Struct) relativ lange dauern und damit die Performance des Spiels massiv verschlechtern wenn Structs sehr häufig als Parameter übergeben werden! Zudem funktioniert das obige Beispiel für Klassen nicht mit Structs, da ja die gesamte Struct beim Übergeben kopiert wird:
Das selbe Prinzip gilt ähnlich auch für [[CSharp#Structs|Structs]]. Da Structs allerdings [[CSharp#Datentypen|value types]] sind, wird beim Übergeben einer Struct als Parameter nicht nur eine Referenz, sondern der komplette Inhalt der Struct kopiert! Dies kann je nach Inhalt der Struct (z.B. 16 float Werte bei einer Matrix-Struct) relativ lange dauern und damit die Performance des Spiels massiv verschlechtern wenn Structs sehr häufig als Parameter übergeben werden! Das obige Beispiel für Klassen funktioniert mit Structs daher nichtmehr:


<source lang="csharp">
<source lang="csharp">
Zeile 66: Zeile 66:
   public void ChangeVector2(Vector3 vector)
   public void ChangeVector2(Vector3 vector)
   {
   {
     vector.x = 3.0;
     vector.x = 4.0;
     vector.y = 3.0;
     vector.y = 4.0;
     vector.z = 3.0;
     vector.z = 4.0;
   }
   }
}
}
Zeile 100: Zeile 100:
== Call by Reference ==
== Call by Reference ==


== Rückgabewerte == [[Kategorie:Code-Beispiele]]
Implizit gilt bei C# also call by value für Parameterübergaben, es kann allerdings auch explizit ein call by reference erzwungen werden. Dazu gibt es das Schlüsselwort '''ref''', welches vor die Parameter einer Methode geschrieben werden kann. Dies hat dann zur Folge dass keine Kopie, sondern direkt die Referenz auf die entsprechende Klasse oder Struct übergeben wird. Schauen wir uns die call by value Code-Beispiele mit der Verwendung von call by reference an:
 
<source lang="csharp">
class Test
{
  public int number;
 
  public Test(int number)
  {
    this.number = number;
  }
}
 
public class MyApp
{
  public static void Main()
  {
    Test test = new Test(7);
    ChangeNumber1(ref test);
    System.Console.WriteLine(test.number);  // gibt 3 aus
    ChangeNumber2(ref test);
    System.Console.WriteLine(test.number);  // gibt 4 aus
  }
 
  public void ChangeNumber1(ref Test test)
  {
    test = new Test(3);
  }
  public void ChangeNumber2(ref Test test)
  {
    test.number = 4;
  }
}
</source>
<source lang="csharp">
public class MyApp
{
  public static void Main()
  {
    Vector3 test = new Vector3(7.0f);
    ChangeVector1(ref test);
    System.Console.WriteLine(test);  // gibt {X:3 Y:3 Z:3} aus
    ChangeVector2(ref test);
    System.Console.WriteLine(test);  // gibt auch {X:4 Y:4 Z:4} aus
  }
 
  public void ChangeVector1(ref Vector3 vector)
  {
    vector = new Vector3(3.0);
  }
  public void ChangeVector2(ref Vector3 vector)
  {
    vector.x = 4.0;
    vector.y = 4.0;
    vector.z = 4.0;
  }
}
</source>
 
Call by reference funktioniert für Structs genauso wie für Klassen. Structs lassen sich somit effizienter übergeben, da keine kompletten Kopien mehr erstellt werden müssen. Allerdings muss man aufpassen dass man beim Ändern einer so übergebenen Struct direkt das ursprüngliche Objekt ändert, was standardmäßig nicht der Fall ist.
 
Gerade an Codestellen die häufig durchlaufen werden empfielt es sich im Hinblick auf die Performance das call by reference zu nutzen. Die häufig verwendeten Structs wie z.B. die Vector3-Struct verfügen selber bereits über entsprechende statische Methoden für verschiedene Rechenoperationen wie z.B.:
<source lang="csharp">
void Vector3.Add(ref Vector3 value1, ref Vector3 value2, out Vector3 result);
void Vector3.Multiply(ref Vector3 value1, float scaleFactor, out Vector3 result);
...
</source>
Diese sind wesentlich Effizienter wie ihre pendants mit call by value:
<source lang="csharp">
Vector3 sum = Vector3.Add(Vector3 value1, Vector2 value2);
Vector3 scaledVec = Vector3.Multiply(Vector3 value1, float scaleFactor);
...
Vector3 sum = vector1 + vector2;
Vector3 scaledVec = vector1 * scaleFactor;
...
</source>
 
Das '''out''' Schlüsselwort das in den Beispielmethoden ebenfalls verwendet wird dient zum deklarieren von Rückgabeparametern. Diese werden im nächsten Abschnitt erläutert.
 
== Rückgabeparameter ==
 
== Verwendung von Structs ==
 
http://msdn.microsoft.com/en-us/library/0taef578.aspx
 
 
[[Kategorie:Code-Beispiele]]