schnellste Möglichkeit, Daten von einem Thread an einen anderen zu übergeben

8

Ich benutze boost spsc_queue um meine Sachen von einem Thread zum anderen zu bewegen. Es ist einer der kritischen Stellen in meiner Software, also möchte ich es so schnell wie möglich machen. Ich habe dieses Testprogramm geschrieben:

%Vor%

Kompiliere Flags:

%Vor%

Auf meinem Rechner: RHEL 7.1, gcc 4.8.3, Xeon E5-2690 v3 empfange ich 290-300 Nanosekunden.

  • Wie gut ist meine Testanwendung? Misst ich die "spsc_queue" -Latenz richtig?
  • Was ist die aktuelle branchenbeste Zeit, um Daten von einem Thread an einen anderen zu übergeben?
  • Ist es eine gute Wahl, boost spsc_queue zu verwenden, um Daten von einem Thread in einen anderen zu verschieben?
  • Können Sie etwas schneller als spsc_queue empfehlen?
  • Können Sie einen Code schreiben, der gleich viel schneller funktioniert?

upd: Warteschlangenmechanismus ist erforderlich. wenn der erste Thread Daten alle 1000 Nanosekunden erzeugt, aber der zweite Thread 10 000 Nanosekunden, um einen einzelnen Gegenstand zu verarbeiten, muss ich mehrere Gegenstände für eine kurze Zeitspanne "anreihen". Aber meine "Warteschlange" ist nie "zu groß". Fixed-Size-Short-Ring-Puffer muss ausreichen.

upd2 Kurz gesagt lautet die Frage: Was ist die schnellste einzelne Producer-Single-Consumer-Queue (am wahrscheinlichsten auf Ringbuffer mit fester Größe)? Ich benutze Boost spsc_queue und erreiche ~ 300 ns Latenz, können Sie etwas schneller vorschlagen?

upd3 In Java gibt es einen Disruptor, der 50 ns Latenz Ссылка Haben wir etwas in C ++ mit der gleichen 50 ns Latenz?

    
javapowered 08.04.2015, 06:42
quelle

3 Antworten

5

Da Sie int s haben, messen Sie (im Idealfall) die Gesamtlatenz zwischen einem Aufruf von push() an die Zeit pop() gibt true zurück.

Das macht keinen Sinn : Der Consumer-Thread ist eifrig polling die Warteschlange, das heißt, er loopt und prüft eifrig, ob pop einen Wert abgerufen hat.

  • Das ist verschwenderisch und
  • Wenn Sie die Latenz minimieren möchten, ist Polling sicher nicht der Weg

Wenn (IFF) die Latenz (für ein einzelnes Element) minimiert werden soll, würde meine Schätzung die Verwendung eines Synchronisierungsmechanismus für die Signalisierung sein, spsc_queue , soweit ich das beurteilen kann, sieht dies nicht vor. (Sie benötigen einen Container oder eine benutzerdefinierte Lösung, in der Sie eine Art Zustandsvariable / Event, ...)

Wenn Sie (IFF) jedoch den Durchsatz maximieren möchten (Elemente pro Zeit), ist es weniger sinnvoll, die Latenz für ein "Aufwachen" eines (einzelnen) Elements zu messen. In diesem Fall möchten Sie die Parallelität, die Sie haben, bestmöglich nutzen, da wird in einem Kommentar erwähnt :

  

Der schnellste Weg zur Datenübermittlung besteht oft darin, für jeden Datenblock einen einzelnen Thread zu verwenden. Das heißt, verwenden Sie nur die in den Daten vorhandene Parallelität.

Adressierung Ihrer Aufzählungspunkte:

  • Wie gut ist die Test App: Ich denke nicht, dass es viel Sinn macht.

    • Es ist scheduledAt in einer atomaren Datei erforderlich, da Sie sie aus einem Thread schreiben und von einem anderen lesen. Sonst hast du UB.
    • Offensichtlich jeder Unterschied der Messung. Dies ist ein reiner Messfehler und sagt nichts über die inhärente Latenz aus. (Sie könnten versuchen, einen aggregierten struct {int val; int64_t time; }; in die Warteschlange zu setzen und dadurch den atomaren Zaun zu vermeiden.
  • Aktuelle beste Zeit der Branche : keine Ahnung. Nicht sicher, ob sich jemand darum kümmert. (Vielleicht in etwas Kernel-Zeug?)

  • Wahl von spsc_queue : Ich denke nicht, dass es eine gute Wahl ist, weil es Abfragen erfordert.

  • schneller als spsc_queue? : Siehe oben. Verwenden Sie Benachrichtigungen ohne Abfrage.

  • schreibe einen Code, der gleich viel schneller funktioniert? : Nein. Oder besser gesagt, ich werde es nicht tun. = & gt;

Um die Antwort des Mannes zu zitieren:

  
  1. Sie definieren das Problem und wählen einen geeigneten Synchronisationsmechanismus
  2.   

Das Problem mit Ihrer Frage ist, dass keine Problemdefinition vorliegt.

Soweit es mich betrifft, scheint die Cross-Thread-Benachrichtigungslatenz im Kontext eines User-Land-Prozesses auf einem normalen Betriebssystem völlig irrelevant zu sein. Was ist Ihr Anwendungsfall?

    
Martin Ba 08.04.2015 11:18
quelle
2

Erstens ist das Schreiben eines solchen Testprogramms völlig nutzlos. Sie arbeiten nicht mit den Daten, daher sind die Ergebnisse verzerrt. Zweitens verwendet Ihr Test usleep () zwischen Pushs - bei dieser Rate können Sie jede Art von Synchronisationsgrundelement verwenden. Es scheint auch, dass Ihre Consumer () nie beendet wird ...

Die Art, wie Sie so etwas implementieren, ist die folgende:

  1. Sie definieren das Problem und wählen einen geeigneten Synchronisationsmechanismus aus
  2. Sie implementieren die Software
  3. Sie profilieren die Software, um potenzielle Hotspots zu identifizieren
  4. Sie optimieren basierend auf den Ergebnissen des vorherigen Schritts und wiederholen.

Sie benötigen bereits erste Erfahrungen oder Sie können versuchen, verschiedene Ansätze zu implementieren und zu sehen, was am besten funktioniert.

    
man 08.04.2015 07:13
quelle
0

Es hängt von der Semantik der Anwendung ab und davon, wie viele Threads beteiligt sind. Bis jetzt betrachten Sie rohe Latenz. Mit mehr Threads könnte auch die Skalierung eine interessante Metrik sein.

Für den Fall mit zwei Threads könnten atomare Aktualisierungen an einem einzelnen Speicherort, vorzugsweise in einer Cache-Zeile, die von keinen anderen Operationen berührt wird, schneller sein, wenn das, was Sie mit den abgerufenen Daten tun, dies erlaubt.

    
Aaron Altman 08.04.2015 12:12
quelle