Das Buch "Wettbewerb in C #. Asynchrone, parallele und Multithread-Programmierung. 2nd int. ed. "

BildHallo habrozhiteli! Wenn Sie Angst vor wettbewerbsfähiger und Multithread-Programmierung haben, ist dieses Buch für Sie geschrieben. Stephen Cleary verfügt über 85 Rezepte für die Arbeit mit .NET und C # 8.0 für die parallele Verarbeitung und asynchrone Programmierung. Der Wettbewerb ist bereits zur anerkannten Methode für die Entwicklung hochskalierbarer Anwendungen geworden, aber die gleichzeitige Programmierung bleibt eine entmutigende Aufgabe. Detaillierte Beispiele und Kommentare zum Code helfen zu verstehen, wie moderne Tools den Abstraktionsgrad erhöhen und die wettbewerbsfähige Programmierung vereinfachen. Sie lernen, wie Sie Async verwenden und auf asynchrone Vorgänge warten, die Funktionen des Codes durch die Verwendung von asynchronen Threads erweitern und das Potenzial der parallelen Programmierung mit der TPL-Datenflussbibliothek erkunden.Erstellen Sie Datenfluss-Pipelines mit der TPL-Datenflussbibliothek, verwenden Sie das LINQ-basierte System. Reaktive Funktionen, verwenden Sie threadsichere und unveränderliche Sammlungen, führen Sie Unit-Tests von wettbewerbsfähigem Code durch, übernehmen Sie die Kontrolle über den Thread-Pool, implementieren Sie die korrekte kooperative Stornierung, analysieren Sie Skripte, um wettbewerbsfähige Methoden zu kombinieren , alle Funktionen der asynchron kompatiblen objektorientierten Programmierung nutzen, Adapter für Code erkennen und erstellen, der alte Stile der asynchronen Programmierung verwendet.Analysieren Sie Skripte, um wettbewerbsfähige Methoden zu kombinieren, nutzen Sie alle Funktionen der asynchron kompatiblen objektorientierten Programmierung, erkennen und erstellen Sie Adapter für Code, der alte Stile der asynchronen Programmierung verwendet.Analysieren Sie Skripte, um wettbewerbsfähige Methoden zu kombinieren, nutzen Sie alle Funktionen der asynchron kompatiblen objektorientierten Programmierung, erkennen und erstellen Sie Adapter für Code, der alte Stile der asynchronen Programmierung verwendet.

Grundlagen der parallelen Programmierung


4.1. Parallele Datenverarbeitung


Aufgabe


Es gibt eine Sammlung von Daten. Sie müssen mit jedem Datenelement den gleichen Vorgang ausführen. Diese Operation ist rechnerisch begrenzt und kann einige Zeit dauern.

Entscheidung


Der Typ Parallel enthält die ForEach-Methode, die speziell für diese Aufgabe entwickelt wurde. Im folgenden Beispiel wird eine Sammlung von Matrizen abgerufen und diese Matrizen gedreht:

void RotateMatrices(IEnumerable<Matrix> matrices, float degrees)
{
   Parallel.ForEach(matrices, matrix => matrix.Rotate(degrees));
}

Es kann Situationen geben, in denen der Zyklus vorzeitig abgebrochen werden muss (z. B. wenn ein ungültiger Wert erkannt wird). Im folgenden Beispiel wird jede Matrix umgekehrt. Wenn jedoch eine ungültige Matrix gefunden wird, wird die Schleife unterbrochen:

void InvertMatrices(IEnumerable<Matrix> matrices)
{
   Parallel.ForEach(matrices, (matrix, state) =>
   {
      if (!matrix.IsInvertible)
        state.Stop();
      else
        matrix.Invert();
   });
}

Dieser Code verwendet ParallelLoopState.Stop, um die Schleife zu stoppen und weitere Aufrufe des Schleifenkörpers zu verhindern. Beachten Sie, dass der Zyklus parallel ist. Daher können bereits andere Aufrufe des Zykluskörpers erfolgen, einschließlich Aufrufen von Elementen, die dem aktuellen folgen. Wenn im angegebenen Codebeispiel die dritte Matrix nicht invertierbar ist, wird der Zyklus unterbrochen und neue Matrizen werden nicht verarbeitet. Es kann sich jedoch herausstellen, dass bereits andere Matrizen verarbeitet werden (z. B. die vierte und fünfte).

Eine häufigere Situation tritt auf, wenn Sie eine parallele Schleife abbrechen müssen. Dies ist nicht dasselbe wie das Stoppen eines Zyklus. Der Zyklus stoppt von innen und wird von außen abgebrochen. Mit der Schaltfläche Abbrechen kann beispielsweise die CancellationTokenSource abgebrochen werden, wodurch die parallele Schleife wie im folgenden Beispiel abgebrochen wird:

void RotateMatrices(IEnumerable<Matrix> matrices, float degrees,
      CancellationToken token)
{
   Parallel.ForEach(matrices,
         new ParallelOptions { CancellationToken = token },
         matrix => matrix.Rotate(degrees));
}

Es sollte beachtet werden, dass jede parallele Aufgabe in einem anderen Thread ausgeführt werden kann, daher muss jeder gemeinsame Zustand geschützt werden. Das folgende Beispiel invertiert jede Matrix und zählt die Anzahl der Matrizen, die nicht invertiert werden konnten:

// :     .
//      
//    .
int InvertMatrices(IEnumerable<Matrix> matrices)
{
  object mutex = new object();
  int nonInvertibleCount = 0;
  Parallel.ForEach(matrices, matrix =>
  {
     if (matrix.IsInvertible)
    {
       matrix.Invert();
    }
    else
    {
       lock (mutex)
      {
         ++nonInvertibleCount;
      }
    }
  });
  return nonInvertibleCount;
}

Erläuterung


Die Parallel.ForEach-Methode bietet eine parallele Verarbeitung für eine Folge von Werten. Eine ähnliche PLINQ-Lösung (Parallel LINQ) bietet nahezu dieselben Funktionen in der LINQ-ähnlichen Syntax. Einer der Unterschiede zwischen Parallel und PLINQ besteht darin, dass PLINQ davon ausgeht, dass alle Kerne auf dem Computer verwendet werden können, während Parallel dynamisch auf sich ändernde Prozessorbedingungen reagieren kann.

Parallel.ForEach implementiert eine parallele foreach-Schleife. Wenn Sie eine parallele for-Schleife ausführen müssen, unterstützt die Parallel-Klasse auch die Parallel.For-Methode. Die Parallel.For-Methode ist besonders nützlich, wenn Sie mit mehreren Datenfeldern arbeiten, die einen einzelnen Index erhalten.

Weitere Informationen


In Rezept 4.2 wird die parallele Aggregation einer Reihe von Werten einschließlich der Summierung und Berechnung von Durchschnittswerten erörtert.

Rezept 4.5 behandelt die Grundlagen von PLINQ.

Kapitel 10 befasst sich mit der Stornierung.

4.2. Parallele Aggregation


Aufgabe


Es ist erforderlich, die Ergebnisse am Ende der Paralleloperation zu aggregieren (Beispiele für die Aggregation sind die Summierung von Werten oder die Berechnung des Durchschnitts).

Entscheidung


Zur Unterstützung der Aggregation verwendet die Parallel-Klasse das Konzept lokaler Werte - Variablen, die lokal in einer parallelen Schleife vorhanden sind. Dies bedeutet, dass der Schleifenkörper einfach direkt auf den Wert zugreifen kann, ohne dass eine Synchronisierung erforderlich ist. Wenn die Schleife bereit ist, alle lokalen Ergebnisse zu aggregieren, erfolgt dies mithilfe des localFinally-Delegaten. Es ist zu beachten, dass der localFinally-Delegat den Zugriff auf die Variable nicht synchronisieren muss, um das Ergebnis zu speichern. Beispiel für eine parallele Summierung:

// :     .
//      
//    .
int ParallelSum(IEnumerable<int> values)
{
  object mutex = new object();
  int result = 0;
  Parallel.ForEach(source: values,
        localInit: () => 0,
        body: (item, state, localValue) => localValue + item,
        localFinally: localValue =>
       {
          lock (mutex)
             result += localValue;
       });
  return result;
}

Parallel LINQ bietet eine umfassendere Aggregationsunterstützung als die Parallel-Klasse:

int ParallelSum(IEnumerable<int> values)
{
   return values.AsParallel().Sum();
}

Okay, das war ein billiger Trick, da PLINQ eine Unterstützung für viele gängige Operatoren (wie Sum) bietet. PLINQ bietet auch generische Aggregationsunterstützung mit dem Aggregatoperator:

int ParallelSum(IEnumerable<int> values)
{
  return values.AsParallel().Aggregate(
        seed: 0,
        func: (sum, item) => sum + item
  );
}

Erläuterung


Wenn Sie die Parallel-Klasse bereits verwenden, sollten Sie deren Aggregationsunterstützung verwenden. In anderen Fällen ist die PLINQ-Unterstützung normalerweise ausdrucksstärker und der Code ist kürzer.

Weitere Informationen


Rezept 4.5 beschreibt die Grundlagen von PLINQ.

4.3. Parallelanruf


Aufgabe


Es gibt eine Reihe von Methoden, die parallel aufgerufen werden sollten. Diese Methoden sind (meistens) unabhängig voneinander.

Entscheidung


Die Parallel-Klasse enthält eine einfache Invoke-Methode, die für solche Szenarien entwickelt wurde. Im folgenden Beispiel wird das Array in zwei Teile geteilt und die beiden Hälften werden unabhängig voneinander verarbeitet:

void ProcessArray(double[] array)
{
   Parallel.Invoke(
         () => ProcessPartialArray(array, 0, array.Length / 2),
         () => ProcessPartialArray(array, array.Length / 2, array.Length)
   );
}

void ProcessPartialArray(double[] array, int begin, int end)
{
   // ,   ...
}

Sie können auch ein Array von Delegaten an die Parallel.Invoke-Methode übergeben, wenn die Anzahl der Aufrufe vor der Ausführung unbekannt ist:

void DoAction20Times(Action action)
{
   Action[] actions = Enumerable.Repeat(action, 20).ToArray();
   Parallel.Invoke(actions);
}

Parallel.Invoke unterstützt die Stornierung wie andere Methoden der Parallel-Klasse:

void DoAction20Times(Action action, CancellationToken token)
{
   Action[] actions = Enumerable.Repeat(action, 20).ToArray();
   Parallel.Invoke(new ParallelOptions { CancellationToken = token },
        actions);
}

Erläuterung


Die Parallel.Invoke-Methode ist eine großartige Lösung für einen einfachen parallelen Aufruf. Ich stelle fest, dass es nicht so gut für Situationen geeignet ist, in denen es notwendig ist, eine Aktion für jedes Eingabedatenelement zu aktivieren (es ist besser, Parallel.ForEach dafür zu verwenden) oder wenn jede Aktion eine Ausgabe erzeugt (stattdessen sollte Parallel LINQ verwendet werden).

Weitere Informationen


In Rezept 4.1 wird die Parallel.ForEach-Methode erläutert, die für jedes Datenelement eine Aktion ausführt.

Rezept 4.5 befasst sich mit Parallel LINQ.

Über den Autor


Stephen Cleary , ein erfahrener Entwickler, ist von ARM zu Azure gewechselt. Er trug zur Open Source Boost C ++ - Bibliothek bei und veröffentlichte mehrere proprietäre Bibliotheken und Dienstprogramme.

»Weitere Informationen zum Buch finden Sie auf der Website des Herausgebers.
» Inhalt
» Auszug

für Khabrozhiteley 25% Rabatt auf den Gutschein - Cleary

Nach Zahlung der Papierversion des Buches wird ein elektronisches Buch per E-Mail verschickt.

All Articles