In seinem Buch stellt The C++ Standard Library (Second Edition)
Nicolai Josuttis fest, dass Lambdas vom Compiler besser optimiert werden können als einfache Funktionen.
Darüber hinaus optimieren C ++ - Compiler Lambdas besser als normale Funktionen. (Seite 213)
Warum ist das so?
Ich dachte, wenn es um Inlining geht, sollte es keinen Unterschied mehr geben. Der einzige Grund, an den ich denken könnte, ist, dass Compiler möglicherweise einen besseren lokalen Kontext mit Lambdas haben und so mehr Annahmen treffen und mehr Optimierungen durchführen können.
c++
optimization
c++11
lambda
compiler-optimization
Stephan Dollberg
quelle
quelle
Antworten:
Der Grund dafür ist, dass Lambdas Funktionsobjekte sind. Wenn Sie sie also an eine Funktionsvorlage übergeben, wird eine neue Funktion speziell für dieses Objekt instanziiert. Der Compiler kann somit den Lambda-Aufruf trivial inline.
Für Funktionen, andererseits gilt die alte Einschränkung: eine Funktion Zeiger auf die Funktionsvorlage übergeben wird, und Compiler haben traditionell eine Menge Probleme Anrufe über Funktionszeiger inlining. Sie können theoretisch inline sein, aber nur, wenn auch die umgebende Funktion inline ist.
Betrachten Sie als Beispiel die folgende Funktionsvorlage:
Nennen wir es mit einem Lambda wie diesem:
Ergebnisse in dieser Instanziierung (vom Compiler erstellt):
… Der Compiler weiß
_some_lambda_type::operator ()
und kann ihn trivial inline aufrufen. (Und das Aufrufen der Funktionmap
mit einem anderen Lambda würde eine neue Instanziierung erzeugen,map
da jedes Lambda einen eigenen Typ hat.)Beim Aufruf mit einem Funktionszeiger sieht die Instanziierung jedoch wie folgt aus:
… Und zeigt hier
f
auf eine andere Adresse für jeden Aufruf vonmap
und daher kann der Compiler keine Inline-Aufrufe an senden , esf
sei denn, der umgebende Aufruf vonmap
wurde ebenfalls inline geschrieben, damit der Compilerf
in eine bestimmte Funktion auflösen kann .quelle
std::sort
ist das klassische Beispiel dafür, dass die Verwendung von Lambdas anstelle eines Funktionszeigers hier eine bis zu siebenfache (wahrscheinlich mehr, aber ich habe keine Daten dazu!) Leistungssteigerung bewirkt.std::sort
, odermap
in meinem Beispiel) und das Lambda selbst. Das Lambda ist normalerweise klein. Die andere Funktion - nicht unbedingt. Wir befassen uns mit Inlining-Aufrufen des Lambda innerhalb der anderen Funktion.pred
deren Definition sichtbar ist und die gcc v5.3 verwendet,std::find_if(b, e, pred)
nicht inline istpred
, sondernstd::find_if(b, e, [](int x){return pred(x);})
funktioniert. Clang schafft es, beide zu inline, produziert aber mit dem Lambda nicht so schnell Code wie g ++.Denn wenn Sie eine "Funktion" an einen Algorithmus übergeben, übergeben Sie tatsächlich einen Zeiger auf die Funktion, sodass dieser einen indirekten Aufruf über den Zeiger auf die Funktion ausführen muss. Wenn Sie ein Lambda verwenden, übergeben Sie ein Objekt an eine speziell für diesen Typ instanziierte Vorlageninstanz, und der Aufruf der Lambda-Funktion ist ein direkter Aufruf, kein Aufruf über einen Funktionszeiger, sodass die Wahrscheinlichkeit sehr viel höher ist.
quelle