Tut async(launch::async) in C++11 machen, thread-pools veraltet für die Vermeidung von teuren thread erstellen?

Ist es Locker sich auf diese Frage beziehen: Sind std::thread gebündelt in C++11?. Obwohl die Frage unterscheidet sich, das Ziel ist das gleiche:

Frage 1: Macht es noch Sinn die zu verwenden Sie Ihre eigenen (oder 3rd-party-Bibliothek), thread-pools zu vermeiden, teure thread erstellen?

Den Abschluss, die andere Frage war, dass Sie sich nicht darauf verlassen kann std::thread gepoolt werden (es könnte oder könnte es nicht). Allerdings std::async(launch::async) zu haben scheint, eine viel höhere chance zu einem Pool zusammengefasst werden.

Er glaube nicht, dass es gezwungen ist, die Norm, aber IMHO würde ich erwarten, dass alle guten C++11-Implementierungen verwenden würden, thread-pooling, wenn thread-Erstellung ist langsam. Nur auf Plattformen, wo es günstig einen neuen thread erstellen, würde ich erwarten, dass Sie immer laichen einen neuen thread.

Frage 2: Das ist genau das, was ich denke, aber ich habe keine Fakten um das zu beweisen. Ich kann sehr gut falsch sein. Ist es eine Vermutung?

Schließlich, hier habe ich einige Beispiel-code, der erste zeigt, wie ich denke, dass thread-Erstellung können ausgedrückt werden, indem async(launch::async):

Beispiel 1:

 thread t([]{ f(); });
 //...
 t.join();

wird

 auto future = async(launch::async, []{ f(); });
 //...
 future.wait();

Beispiel 2: Feuer-und-vergessen-thread

 thread([]{ f(); }).detach();

wird

 //a bit clumsy...
 auto dummy = async(launch::async, []{ f(); });

 //... but I hope soon it can be simplified to
 async(launch::async, []{ f(); });

Frage 3: Würden Sie es vorziehen, die async Versionen der thread Versionen?


Der rest ist nicht mehr Teil der Frage, aber nur zur Klarstellung:

Warum muss der Rückgabewert zugewiesen werden, um eine dummy-variable?

Leider, in der aktuellen C++11 standard-Kräfte, die Sie erfassen den Rückgabewert von std::async werden, sonst ist der Destruktor ausgeführt wird, die blockiert wird, bis die Aktion beendet. Es wird von einigen als ein Fehler in der standard - (z.B., von Herb Sutter).

Diesem Beispiel aus cppreference.com zeigt es schön:

{
  std::async(std::launch::async, []{ f(); });
  std::async(std::launch::async, []{ g(); });  //does not run until f() completes
}

Weiteren Klärung:

Ich weiß, dass thread-pools können auch andere legitime verwendet, aber in dieser Frage bin ich nur daran interessiert, den Aspekt der Vermeidung von teuren thread-Erstellung Kosten.

Ich denke, es gibt immer noch Situationen, wo thread-pools sind sehr nützlich, vor allem, wenn Sie mehr Kontrolle über Ressourcen.
Zum Beispiel, ein server kann entscheiden, zu handhaben, dass nur eine bestimmte Anzahl von Anfragen gleichzeitig garantieren schnelle Reaktionszeiten und erhöhen die Vorhersagbarkeit der Speichernutzung. Thread-pools sollte in Ordnung sein, hier.

Thread-lokalen Variablen kann auch ein argument sein für die eigene thread-pools, aber ich bin mir nicht sicher, ob es relevant ist, in der Praxis:

  • Erstellen einen neuen thread mit std::thread startet, ohne initialisiert thread-lokalen Variablen. Vielleicht ist dies nicht das, was Sie wollen.
  • In threads hervorgebracht von async es ist etwas unklar für mich, weil der thread hätte wiederverwendet. Von meinem Verständnis, thread-lokale Variablen nicht garantiert werden zurückgesetzt, aber ich kann mich irren.
  • Mit Ihrem eigenen (mit fester Größe) thread-pools, auf der anderen Seite, gibt Ihnen die volle Kontrolle, wenn Sie es wirklich brauchen.
  • "Aber std::async(launch::async) zu haben scheint, eine viel höhere chance zu einem Pool zusammengefasst werden." Nein, ich glaube, seine std::async(launch::async | launch::deferred) werden können gebündelt. Mit nur launch::async die Aufgabe soll gestartet werden, in einem neuen thread, unabhängig davon, was andere tasks ausgeführt werden. Mit der Politik launch::async | launch::deferred dann die Umsetzung, erhält zu wählen, die Politik, aber vor allem wird es, zu verzögern, die Wahl, die Politik. Das heißt, es kann warten, bis ein thread in einem thread-pool zur Verfügung stehen und dann wählen Sie die async-Politik.
  • Soweit ich weiß, nur VC++ verwendet einen thread-pool mit std::async(). Ich bin immer noch neugierig zu sehen, wie Sie die Unterstützung von nicht-trivialen thread_local Destruktoren in einem thread-pool.
  • Das kann sehr einfach realisiert werden, in deren Umsetzung mit RegisterWaitForSingleObject mit dem "Objekt" als das thread-handle. Wenn der thread beendet werden, dessen handle wird signalisiert werden, und der Rückruf in der Warteschlange ausgeführt im thread-pool. Der Rückruf kann dann rufen Sie nicht-trivialen Destruktor für TLS. Ich weiß nicht, ob Sie das tun (noch).
  • Ich trat durch die libstdc++ kommt mit gcc 4.7.2 und festgestellt, dass, wenn die launch-Politik ist nicht genau launch::async dann wird es behandelt, als wäre es nur launch::deferred und nie führt es-asynchron - also in der Tat, diese version von libstdc++ "wählt" immer latente gezwungen, es sei denn sonst.
  • Mein Punkt über thread_local Destruktoren war, dass die Zerstörung auf den thread beenden ist nicht ganz richtig, bei der Verwendung von thread-pools. Wenn eine Aufgabe ausgeführt wird asynchron ausgeführt wird, 'als ob in einem neuen thread', gemäß der Spezifikation, was bedeutet, dass jede async-task bekommt seinen eigenen thread_local Objekte. Ein thread-pool-basierte implementation hat, Besondere Sorgfalt walten, um sicherzustellen, dass die Aufgaben, welche die gleiche backing-thread immer noch so Verhalten, als wenn Sie Ihre eigenen thread_local Objekte. Betrachten Sie dieses Programm: pastebin.com/9nWUT40h
  • Mit "als-ob in einem neuen thread" in der spec-war ein großer Fehler meiner Meinung nach. std::async hätte eine schöne Sache für die Leistung - es hätte der standard kurz ausgeführt-der task-Ausführung-system, natürlich gesichert durch einen thread-pool. Gerade jetzt, es ist nur ein std::thread mit etwas Mist geheftet, um die thread-Funktion in der Lage sein, um einen Wert zurückzugeben. Oh, und Sie hat redundante "latente" Funktionen, die überschneidungen der Arbeit der std::function komplett.
  • Upvote für "den aktuellen standard C++11 Kräfte, die Sie erfassen den Rückgabewert von std::async, da sonst der Destruktor ausgeführt wird, die blockiert wird, bis die Aktion beendet." Ist es möglich, dass 'Zukunft' Verwandte features wurden implementiert mit shared_ptr, so hat es eine bessere Speicherverwaltung und brauchen nicht zu streng / komisch auf Zerstörung Teil?

Schreibe einen Kommentar