Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
SIMD (Einzelanweisung, mehrere Daten) bietet Hardwareunterstützung für die Ausführung eines Vorgangs auf mehreren Datenteilen parallel mit einer einzigen Anweisung. In .NET gibt es eine Reihe von SIMD-beschleunigten Typen unter dem System.Numerics Namespace. SIMD-Vorgänge können auf Hardwareebene parallelisiert werden. Dies erhöht den Durchsatz der vektorisierten Berechnungen, die in mathematischen, wissenschaftlichen und Grafik-Apps üblich sind.
SIMD-beschleunigte Typen in .NET
Die .NET SIMD-beschleunigten Typen enthalten die folgenden Typen:
Die Vector2, Vector3, und Vector4 Typen, die Vektoren mit 2, 3 und 4 Single Werten darstellen.
Zwei Matrixtypen, Matrix3x2die eine 3x2-Matrix darstellen, und Matrix4x4, die eine 4x4-Matrix mit Single Werten darstellt.
Der Plane Typ, der eine Ebene im dreidimensionalen Raum mit Single Werten darstellt.
Der Quaternion Typ, der einen Vektor darstellt, der zum Codieren dreidimensionaler physischer Drehungen mit Single Werten verwendet wird.
Der Vector<T> Typ, der einen Vektor eines angegebenen numerischen Typs darstellt und einen breiten Satz von Operatoren bereitstellt, die von SIMD-Unterstützung profitieren. Die Anzahl einer Vector<T> Instanz ist für die Lebensdauer einer Anwendung festgelegt, aber ihr Wert Vector<T>.Count hängt von der CPU des Computers ab, auf dem der Code ausgeführt wird.
Hinweis
Der Vector<T> Typ ist nicht im .NET Framework enthalten. Sie müssen das NuGet-Paket "System.Numerics.Vectors " installieren, um Zugriff auf diesen Typ zu erhalten.
Die SIMD-beschleunigten Typen werden so implementiert, dass sie mit nicht SIMD beschleunigter Hardware oder JIT-Compilern verwendet werden können. Um SIMD-Anweisungen nutzen zu können, müssen Ihre 64-Bit-Apps von der Laufzeit ausgeführt werden, die den RyuJIT-Compiler verwendet. Ein RyuJIT-Compiler ist in .NET Core und .NET Framework 4.6 und höher enthalten. DIE SIMD-Unterstützung wird nur bei 64-Bit-Prozessoren bereitgestellt.
Wie verwende ich SIMD?
Vor dem Ausführen von benutzerdefinierten SIMD-Algorithmen ist es möglich, zu überprüfen, ob der Hostcomputer SIMD unterstützt, indem Vector.IsHardwareAccelerated verwendet wird, die einen Boolean zurückgibt. Dies garantiert nicht, dass die SIMD-Beschleunigung für einen bestimmten Typ aktiviert ist, ist jedoch ein Indikator, der von einigen Typen unterstützt wird.
Einfache Vektoren
Die primitivsten SIMD-beschleunigten Typen in .NET sind Vector2, Vector3, und Vector4 Typen, die Vektoren mit 2, 3 und 4 Single Werten darstellen. Im folgenden Beispiel wird Vector2 verwendet, um zwei Vektoren zu addieren.
var v1 = new Vector2(0.1f, 0.2f);
var v2 = new Vector2(1.1f, 2.2f);
var vResult = v1 + v2;
Es ist auch möglich, .NET-Vektoren zum Berechnen anderer mathematischer Eigenschaften von Vektoren wie Dot product
, Transform
, Clamp
und so weiter zu verwenden.
var v1 = new Vector2(0.1f, 0.2f);
var v2 = new Vector2(1.1f, 2.2f);
var vResult1 = Vector2.Dot(v1, v2);
var vResult2 = Vector2.Distance(v1, v2);
var vResult3 = Vector2.Clamp(v1, Vector2.Zero, Vector2.One);
Matrix
Matrix3x2, die eine 3x2-Matrix und Matrix4x4, die eine 4x4-Matrix darstellt. Kann für matrixbezogene Berechnungen verwendet werden. Im folgenden Beispiel wird die Multiplikation einer Matrix mit der entsprechenden Transponierungsmatrix mithilfe von SIMD veranschaulicht.
var m1 = new Matrix4x4(
1.1f, 1.2f, 1.3f, 1.4f,
2.1f, 2.2f, 3.3f, 4.4f,
3.1f, 3.2f, 3.3f, 3.4f,
4.1f, 4.2f, 4.3f, 4.4f);
var m2 = Matrix4x4.Transpose(m1);
var mResult = Matrix4x4.Multiply(m1, m2);
Vektor<T>
Dies Vector<T> ermöglicht die Verwendung längerer Vektoren. Die Anzahl einer Vector<T> Instanz ist fest, aber ihr Wert Vector<T>.Count hängt von der CPU des Computers ab, auf dem der Code ausgeführt wird.
Im folgenden Beispiel wird veranschaulicht, wie die elementweise Summe zweier Arrays mithilfe von Vector<T> berechnet wird.
double[] Sum(double[] left, double[] right)
{
if (left is null)
{
throw new ArgumentNullException(nameof(left));
}
if (right is null)
{
throw new ArgumentNullException(nameof(right));
}
if (left.Length != right.Length)
{
throw new ArgumentException($"{nameof(left)} and {nameof(right)} are not the same length");
}
int length = left.Length;
double[] result = new double[length];
// Get the number of elements that can't be processed in the vector
// NOTE: Vector<T>.Count is a JIT time constant and will get optimized accordingly
int remaining = length % Vector<double>.Count;
for (int i = 0; i < length - remaining; i += Vector<double>.Count)
{
var v1 = new Vector<double>(left, i);
var v2 = new Vector<double>(right, i);
(v1 + v2).CopyTo(result, i);
}
for (int i = length - remaining; i < length; i++)
{
result[i] = left[i] + right[i];
}
return result;
}
Bemerkungen
SIMD ist wahrscheinlicher, einen Engpass zu entfernen und den nächsten verfügbar zu machen, z. B. Speicherdurchsatz. Im Allgemeinen variiert der Leistungsvorteil der Verwendung von SIMD je nach spezifischem Szenario und kann in einigen Fällen sogar schlechter als einfacherer nicht SIMD-äquivalenter Code ausgeführt werden.