Ist mit std::async oft für kleine Aufgaben performance-freundlich?
Geben ein paar Informationen zum hintergrund, ich bin Verarbeitung einer Datei gespeichert haben, und nach der Verwendung des regulären Ausdrucks, so teilen Sie die Datei in die Komponente Gegenstände, die ich dann verarbeiten muss, das Objekt die Daten basierend auf welche Art von Objekt es sich handelt.
Mein Aktueller Gedanke ist die Verwendung von Parallelität, um ein wenig etwas von einem performance-Gewinn, da das laden jedes Objekt ist unabhängig von einander. So, ich werde zu definieren, eine LoadObject
- Funktion, die Annahme einer std::string
für jede Art von Objekt, ich werde zu Handhabung und rufen dann std::async
wie folgt:
void LoadFromFile( const std::string& szFileName )
{
static const std::regex regexObject( "=== ([^=]+) ===\\n((?:.|\\n)*)\\n=== END \\1 ===", std::regex_constants::ECMAScript | std::regex_constants::optimize );
std::ifstream inFile( szFileName );
inFile.exceptions( std::ifstream::failbit | std::ifstream::badbit );
std::string szFileData( (std::istreambuf_iterator<char>(inFile)), (std::istreambuf_iterator<char>()) );
inFile.close();
std::vector<std::future<void>> vecFutures;
for( std::sregex_iterator itObject( szFileData.cbegin(), szFileData.cend(), regexObject ), end; itObject != end; ++itObject )
{
//Determine what type of object we're loading:
if( (*itObject)[1] == "Type1" )
{
vecFutures.emplace_back( std::async( LoadType1, (*itObject)[2].str() ) );
}
else if( (*itObject)[1] == "Type2" )
{
vecFutures.emplace_back( std::async( LoadType2, (*itObject)[2].str() ) );
}
else
{
throw std::runtime_error( "Unexpected type encountered whilst reading data file." );
}
}
//Make sure all our tasks completed:
for( auto& future : vecFutures )
{
future.get();
}
}
Beachten Sie, dass es mehr als 2 Arten in der Anwendung (dies war nur ein kurzes Beispiel) und möglicherweise Tausende von Objekten in die Datei gelesen werden.
Ich bin mir bewusst, dass die Schaffung von zu vielen threads ist oft schlecht für die Leistung, wenn es überschreitet die maximale hardware-Parallelität durch Kontext-switches, aber wenn ich mich erinnere richtig die C++ - Laufzeit-soll überwachen Sie die Anzahl der threads, die erstellt und Zeitplan std::async
angemessen (ich glaube im Fall von Microsoft Ihre ConcRT-Bibliothek ist verantwortlich für diese?), also, der obige code kann immer noch zu einer Leistungsverbesserung führen?
Vielen Dank im Voraus!
- Der obige code kann in der Tat Ergebnis in performance-Verbesserung, aber ich würde sagen, es hängt von der Menge der Arbeit, die jede
LoadTypeX
tut. Ist es genug zu überwiegen, der overhead durch Sie entstehen in deinem Haupt-thread für starten und warten und synchronisieren? Nicht zu vergessen die erhöhte Anzahl von cache-misses und false teilhaben. Und andere Sanktionen im Zusammenhang mit Multithreading-Programmierung. Also, wenn Sie Ihre Objekte groß sind und Ihre asynchrone laden Funktionen sind dabei erhebliche Arbeit, ich würde sagen, es ist wohl Wert es. Aber warum gehst du nicht einfach Messen? - Unrelated: erstellen Sie einen Vektor von 100 Standard-futures konstruiert, und dann anfügen Ihre real-futures am Ende. Aufruf
get()
auf diese default-konstruiert futures Ergebnisse zu undefiniertem Verhalten. - Haben Sie profiliert Ihren code? Ich hätte erwartet, dass die I/O-Kosten für Zwerg die Verarbeitung Kosten bis zu dem Punkt, wo der Gewinn aus der Aufteilung der Verarbeitung in die Gewinde vielleicht nicht messbar.
- Streng genommen, gibt es keine Möglichkeit zu wissen. Sie wissen nicht, wie oder Wann
std::async
läuft eine Aufgabe. Alles, was Sie wissen, ist, dass, wennfuture::get
Renditen, das Ergebnis fertig sein wird. Die Aufgabe ausführen, asynchron in einem anderen thread oder in eine Faser, oder es könnte sogar synchron laufen, wenn Sie anrufenget
. Letzteres ist eine Art von "Betrug", aber es ist zulässig.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Nicht. Wenn der asynchrone Aufgaben sind in der Tat asynchron ausführen (und nicht als latente), dann ist alles, was erforderlich ist, dass Sie so ausgeführt, als ob in einem neuen thread. Es ist vollkommen gültig für einen neuen thread angelegt und gestartet, die für jede Aufgabe, ohne Rücksicht auf die hardware, die der beschränkten Kapazität für Parallelität.
Gibt es einen Hinweis:
Dies ist jedoch nicht-normativen und in jedem Fall zeigt es, daß einmal keine mehr Parallelität ausgenutzt werden kann, die Aufgaben kann verzögert werden, und somit ausgeführt, wenn jemand wartet auf das Ergebnis, anstatt immer noch asynchron und läuft sofort nach einem der vorherigen asynchronen tasks abgeschlossen ist, wie es wünschenswert wäre, für die maximale Parallelität.
Ist, dass, wenn wir 10 lange laufende Aufgaben und die Umsetzung kann nur ausführen, 4 parallel, dann die ersten 4 asynchrone und dann die letzten 6 verschoben werden kann. Warten auf den futures in der Folge führen Sie die zurückgestellten Aufgaben auf einen einzigen thread in Folge, wodurch die parallele Ausführung für diese Aufgaben.
Die note muss auch sagen, dass anstelle der Vertagung der Aufruf, die Auswahl des politischen verschoben werden kann. Das heißt, die Funktion kann immer noch laufen asynchron, aber diese Entscheidung kann hinausgezögert werden, sagen wir, bis eine der früheren Aufgaben abgeschlossen, zu befreien, einen Kern für eine neue Aufgabe. Aber nochmals, dies ist nicht erforderlich, der Hinweis ist nicht-normativ, und soweit ich weiß die Microsoft-Implementierung ist die einzige, die auf diese Weise verhält. Als ich sah auf einem anderen Umsetzung, libc++, es einfach ignoriert diesen Hinweis zusammen, so dass entweder
std::launch::async
oderstd::launch::any
Politik Ergebnis der asynchronen Ausführung in einem neuen thread.Microsoft-Implementierung scheint in der Tat so Verhalten, wie Sie beschreiben, aber dies ist nicht erforderlich und ein portables Programm kann sich nicht darauf berufen, dass das Verhalten.
Eine Möglichkeit Mobil limit, wie viele threads ausgeführt ist, etwas zu verwenden, wie ein semaphore:
std::async
aufgeschoben werden, bis ein Aufrufwait()
oderget()
gemacht wird oder ob Sie zurückgestellt werden, bis ein thread fertig?