Uwaga
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
SimD (pojedyncza instrukcja, wiele danych) zapewnia obsługę sprzętu do wykonywania operacji na wielu fragmentach danych, równolegle przy użyciu jednej instrukcji. Na platformie .NET znajduje się zestaw typów przyspieszonych przez SIMD w przestrzeni nazw System.Numerics. Operacje SIMD można zrównoleglizować na poziomie sprzętu. Zwiększa to przepływność wektoryzowanych obliczeń, które są wspólne w aplikacjach matematycznych, naukowych i graficznych.
Typy .NET przyspieszone przez SIMD
Typy przyspieszone przez .NET SIMD obejmują następujące typy:
Typy Vector2, Vector3i Vector4 reprezentujące wektory z wartościami 2, 3 i 4 Single .
Dwa typy macierzy, Matrix3x2, który reprezentuje macierz 3x2, i Matrix4x4, który reprezentuje macierz 4x4 wartości Single.
Plane Typ, który reprezentuje płaszczyznę w trójwymiarowej przestrzeni przy użyciu Single wartości.
Quaternion Typ, który reprezentuje wektor używany do kodowania trójwymiarowych rotacji fizycznych przy użyciu Single wartości.
Typ Vector<T> , który reprezentuje wektor określonego typu liczbowego i zapewnia szeroki zestaw operatorów, które korzystają z obsługi SIMD. Vector<T> Liczba wystąpień jest stała dla okresu istnienia aplikacji, ale jej wartość Vector<T>.Count zależy od procesora CPU maszyny, na którym jest uruchomiony kod.
Uwaga / Notatka
Typ Vector<T> nie jest uwzględniony w programie .NET Framework. Aby uzyskać dostęp do tego typu, należy zainstalować pakiet NuGet System.Numerics.Vectors .
Przyspieszone typy SIMD są implementowane w taki sposób, że mogą być używane z nieprzyśpieszonym sprzętem lub kompilatorami JIT. Aby korzystać z instrukcji SIMD, aplikacje 64-bitowe muszą być uruchamiane przez środowisko uruchomieniowe korzystające z kompilatora RyuJIT . Kompilator RyuJIT jest dołączony do platformy .NET Core i w programie .NET Framework 4.6 lub nowszym. Obsługa SIMD jest zapewniana tylko w przypadku procesorów 64-bitowych.
Jak używać simd?
Przed wykonaniem własnych algorytmów SIMD można sprawdzić, czy host obsługuje SIMD, używając polecenia Vector.IsHardwareAccelerated, co zwraca Boolean wartość. Nie gwarantuje to, że przyspieszanie SIMD jest włączone dla określonego typu, ale wskazuje, że przyspieszanie SIMD jest obsługiwane przez niektóre typy.
Wektory proste
Najbardziej podstawowe typy SIMD przyspieszone na platformie .NET to Vector2, Vector3 i Vector4, które reprezentują wektory z wartościami 2, 3 i 4 Single. W poniższym przykładzie użyto Vector2 do dodania dwóch wektorów.
var v1 = new Vector2(0.1f, 0.2f);
var v2 = new Vector2(1.1f, 2.2f);
var vResult = v1 + v2;
Można również użyć wektorów platformy .NET do obliczenia innych właściwości matematycznych wektorów, takich jak Dot product
, Transform
Clamp
i tak dalej.
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);
Matryca
Matrix3x2, który reprezentuje macierz 3x2 i Matrix4x4, która reprezentuje macierz 4x4. Może służyć do obliczeń związanych z macierzą. W poniższym przykładzie pokazano mnożenie macierzy przez jej transponowaną macierz przy użyciu SIMD.
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);
Wektor<T>
Element Vector<T> zapewnia możliwość używania dłuższych wektorów. Liczba wystąpień Vector<T> jest stała, ale jej wartość Vector<T>.Count zależy od procesora CPU maszyny, na którym jest uruchomiony kod.
W poniższym przykładzie pokazano, jak obliczyć sumę elementów dwóch tablic przy użyciu metody Vector<T>.
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;
}
Uwagi
SIMD ma większe prawdopodobieństwo usunięcia jednego wąskiego gardła i ujawnienia następnego, na przykład przepustowości pamięci. Ogólnie rzecz biorąc, korzyści wydajnościowe wynikające z użytkowania SIMD zależą od konkretnego scenariusza, a w niektórych przypadkach może nawet działać gorzej niż prostszy, równoważny kod nie-SIMD.