
Mit meinem humanitären Verstand habe ich immer so gedacht - wenn ein Programmierer weiß, wie man es leistungsfähiger macht, dann muss es leistungsfähiger gemacht werden. Eine produktive Lösung = die richtige Lösung. Eine Programmiersprache ist möglicherweise langsamer als eine andere, und wenn sich herausstellt, wird die Programmiersprache verschwendet.
Sicher - wenn der Entwickler ein Leistungsspezialist ist, wird er für all diese Dinge ertrinken, auch wenn sie falsch sind.
Natürlich ist das alles Unsinn, aber es ist nicht meine Aufgabe, Ihnen davon zu erzählen. Daher kam Andrei Akinshin, Entwickler und Mathematiker, Kandidat für physikalische und mathematische Wissenschaften, Betreuer von BenchmarkDotNet und Perfolizer, Autor des Buches Pro .NET Benchmarking und nur ein sehr, sehr cooler Ingenieur, zu unserem Podcast.
Unten finden Sie ausgewählte Zitate.
Es ist unmöglich, alles in Benchmarks vorherzusehen
Ein Kollege von mir hatte kürzlich Folgendes. Er programmierte am Morgen, alles war gut mit ihm, alles funktionierte schnell. Irgendwann fing alles an zu kleben - Fahrer ist langsam, IDEE, der Browser - alles ist langsam. Er konnte in keiner Weise verstehen, was los war? Und dann wurde mir klar. Er arbeitete an einem schwarzen Laptop, der am Fenster stand. Am Morgen war es ziemlich kühl, und am Nachmittag ging die Sonne auf, der Laptop wurde sehr heiß und wurde thermisch gedrosselt.
Er weiß, dass es so etwas gibt, weiß, dass die physische Umgebung die Leistung beeinflussen kann, und er hat schnell erkannt, was passiert ist. Er hatte ein Modell im Kopf, nach dem die Welt funktioniert, und innerhalb dieses Modells fand er mehr oder weniger schnell heraus, was los war.
Das heißt, die wichtigste Fähigkeit, die beim Benchmarking erworben werden kann, besteht darin, nicht alles in absolut allen Details zu kennen - alle Laufzeiten und die gesamte Hardware. Die Hauptsache ist zu verstehen, wie Sie handeln müssen, um das Problem zu finden, vorzugsweise so schnell wie möglich mit minimalem Aufwand.
Ich werde eine Analogie mit Sprachen geben. Wenn Sie Ihre erste funktionale Programmiersprache lernen, müssen Sie Ihre Einstellung zur Welt leicht ändern - um die Prinzipien der funktionalen Programmierung zu verstehen, wie Sie im Allgemeinen denken müssen. Dann nimmst du die nächste funktionale Sprache X und hast diese Prinzipien bereits im Kopf. Du siehst ein paar Hallo Welt und fängst auch an zu schreiben.
Gleichzeitig kennen Sie möglicherweise einige Nuancen der Sprache nicht. Sie wissen vielleicht nicht, wie bestimmte syntaktische Konstrukte funktionieren, aber das stört Sie nicht so sehr. Sie fühlen sich wohl und schreiben. Ich sah mich einem unverständlichen Verhalten gegenüber - ich las das Handbuch, fand es heraus, eine neue Tatsache drang leicht in Ihr Bild der Welt ein, und Sie gingen weiter. Und Sie werden nie alle Nuancen aller funktionalen Sprachen der Welt lernen, aber der allgemeine Ansatz wird in Ihrem Kopf bleiben.
Ich glaube, dass Sie in jedem Bereich ein ähnliches Niveau erreichen und dann in die Breite gehen müssen.
Irgendwann beim Benchmarking konzentrierte ich mich speziell auf die Messgenauigkeit, auf die Merkmale bestimmter Laufzeiten, ein Stück Eisen, etwas anderes. Dann hörte ich jedes Mal auf, Amerika zu entdecken, und alle Leistungsprobleme fielen in die Klassen, die ich bereits kannte. Und ich ging in die Breite - in Richtung Leistungsanalyse: Was tun mit den Zahlen, die wir gemessen haben? Und in diesem Bereich bin ich noch nicht am Rande des Wissens angelangt. Einige Dinge sind mir bereits klar geworden, aber es liegt noch viel Arbeit vor mir - zu verstehen, wie man all dies in der Praxis anwendet, welche Formeln zu verwenden sind, welche nicht zu verwenden sind, welche Ansätze gut sind und welche nicht.
Benchmarking zum Zwecke des Benchmarking ist nicht das Beste
Es sollte immer einige Anforderungen an die Geschäftsleistung geben, Sie sollten immer verstehen, wonach Sie streben. Wenn Sie keine geschäftlichen Anforderungen haben, macht es auch keinen Sinn, Leistung zu erbringen. Wenn es geschäftliche Anforderungen gibt, beginnen Sie bereits zu verstehen, welche Ansätze Sie zumindest mit dem Auge verwenden können und welche nicht. Wenn nicht, gehen Sie, Benchmarking, überprüfen - welche Ansätze zu Ihren Anforderungen passen.
Und wenn Sie über eine Reihe von Algorithmen, Optionen zum Schreiben von Code, Design und anderen Dingen verfügen und alles in die Anforderungen passt, wählen Sie bereits aus, was mit dem Rest des Projekts, das Ihre Ansichten zur Ästhetik widerspiegelt, konsistenter ist und wie Code richtig geschrieben wird ...
Grob gesagt, wenn ich maximal 10 Elemente in einer Sammlung habe und es zwei Optionen gibt - schreibe einen einfachen Algorithmus für einen Würfel oder einen sehr komplexen für n * log n - schreibe ich einen einfachen für einen Würfel, der für alle klar ist und leicht zu warten und zu ändern ist. Weil ich verstehe, dass er meine Leistungsbeschränkungen niemals durchbrechen wird.
Wenn Sie eine langsame Lösung für einen kleinen Datensatz geschrieben und dann für einen großen Datensatz verwendet haben und keine besonders schlimmen Konsequenzen hatten (normalerweise keine), lassen Sie uns das Problem beheben. Aber im Kopf wird es ein Modell geben, wie diese Fehler in Zukunft vermieden werden können.
Beispielsweise können Sie eine Zusicherung ganz am Anfang der Methode einfügen, damit die Anzahl der Elemente in der Auflistung diese und jene Anzahl nicht überschreitet. Dann sieht der nächste Programmierer, der versehentlich versucht, Ihre Methode zu verwenden, sofort eine Ausnahme und verwendet sie nicht. Solche Dinge kommen mit Erfahrung.
Es gibt ein weiteres Problem - volatile Geschäftsanforderungen. Sie werden sich definitiv ändern - dies ist ein Axiom unserer Realität, es gibt keine Möglichkeit, davon wegzukommen. Mit der Erfahrung können Sie anhand des Auges vorhersagen, wo sich die Anforderungen ändern können, wo es sich lohnt, ein gutes Leistungsniveau festzulegen, wo sich die Last erhöhen kann.
Während diese Intuition nicht vorhanden ist, können Sie durch Ausprobieren sehen, was passiert.
Sie haben immer einen Kompromiss zwischen Leistung und Schönheit
Wenn Sie so effizient wie möglich schreiben, wird Ihr Code höchstwahrscheinlich nur schrecklich und ekelhaft sein - und selbst wenn Sie die Augen vor der Ästhetik verschließen, wird es schwierig zu warten sein, es treten ständig subtile Fehler auf, weil die Architektur schlecht ist, der Code schlecht ist, alles schlecht ist.
Ich denke, Sie müssen sich auf die aktuellen Geschäftsanforderungen konzentrieren und den saubersten, verständlichsten, schönsten und wartbarsten Code darin schreiben. Und in dem Moment, in dem es zu ernten beginnt (oder das Gefühl besteht, dass es bald beginnen wird), ändert sich bereits etwas.
Und selbst wenn Sie sich immer nur auf die Leistung konzentrieren, gibt es keinen perfekt optimierten, maximal produktiven Code. Es bedeutet alles - C # vergessen, alle schönen Sprachen vergessen. Und es ist besser, allgemein in Maschinencodes zu schreiben, da der Assembler auch in der Syntax eingeschränkt ist. Und wenn Sie sofort auf die Bytes schreiben, erhalten Sie eine Leistungssteigerung.
In einigen Fällen erweist sich der schnellste Code als der schönste, offensichtlichste und korrekteste. Aber solche Kompromisse entstehen unvermeidlich in Dutzenden und Hunderten von kleinen Momenten. Nehmen wir an, es gibt so etwas wie das Überprüfen auf eine Verletzung der Array-Grenzen. Sie können zustimmen, dass die Laufzeit sich darum kümmert, dass Sie die Grenzen des Arrays an allen Stellen überprüfen. Wenn Sie sich dem ersten Minuselement zuwenden, erhalten Sie eine Ausnahme und lesen nicht aus dem linken Speicherbereich.
Und für dieses Vertrauen, das Sie definitiv nie vom falschen Gedächtnis abziehen - zahlen Sie mit einem kleinen Stück Leistung. Das heißt, wir verwenden die Leistung als Ressource, um das Programm stabiler, verständlicher und wartbarer zu machen.
Sprache hat keine Eigenschaft wie Leistung
Wenn Sie einen Artikel sehen, bei dem X schneller als Y ist, können Sie den Artikel schließen. Sprache ist eine mathematische Abstraktion. Dies ist ein Regelwerk, nach dem das Programm kompiliert wird. Es hat keine Leistung, es hat keine Leistung, es ist etwas, das in Ihrem Kopf existiert und in einem Texteditor enthalten ist.
Die Leistung ist für bestimmte Laufzeiten, Umgebungen, bestimmte Programme und bestimmte Apishe verfügbar. Wenn Sie all diese Faktoren berücksichtigen, können Sie über die Leistung sprechen. Es gibt jedoch eine kombinatorische Explosion, und Sie können nicht sagen, dass ein Code in dieser Sprache immer schneller ist als ein anderer Code in dieser Sprache, da neue Versionen von Hardware und Laufzeiten herauskommen. Sie werden niemals alle möglichen Kombinationen externer Faktoren in Ihrem Leben durchlaufen. Die Apish, die Sie verwenden, sind grundlegend anders.
Beispielsweise implementierten sie in einer bedingten Sprache in den frühen Entwicklungsstadien eine Methode zum Sortieren unter Verwendung einer Blase. Nun, ich weiß nicht - die Jungs wollten die Veröffentlichung so schnell wie möglich herausbringen und haben die einfachste Sortierung geschrieben, die sie machen konnten. Sie haben es genommen, diese Methode verwendet und es stellte sich heraus, dass es bei Big Data langsamer ist als in einer anderen Sprache, in der Quicksortierung durchgeführt wird. Bedeutet dies, dass Sie über die Leistung einiger Sprachen sprechen können? Nein. Sie können sagen, dass dieser bestimmte Apish aus dieser Sprache auf diesem Betriebssystem, auf dieser Hardware in diesen Umgebungen langsamer arbeitet als ein anderer Apish aus einer anderen Sprache in einer anderen Umgebung. So kann man sagen. Es wird sich jedoch herausstellen, dass es sich um einen sehr langen Textabschnitt handelt, der korrekt formuliert werden muss.
Herkömmlicherweise können wir sagen, dass C ++ in den meisten Fällen schneller als JavaScript ist. Es wäre jedoch richtiger zu sagen, dass C ++ - Programmierer mit guter C ++ - Erfahrung, die in C ++ schreiben, ein Programm schreiben, das wahrscheinlich schneller ist als ein JavaScript-Javascriptor, das etwas schreibt, das in einem Browser funktioniert.
Hier gibt es aber auch viele Vorbehalte. Aber was ist, wenn ein Typ, der in JavaScript geschrieben hat, sagt, dass dies nicht der Fall ist, und dort zu einer Art WebAssembly oder etwas anderem geht, um es zu wiederholen? Oder finden Sie auf GitHub einen JavaScript-Superinterpreter-Compiler, der mit einer um dreieinhalb Syntaxkonstrukte sehr abgeschnittenen Teilmenge von JS arbeitet, aber superschnellen nativen Code erzeugt.
Und dort können Sie, wenn Sie möchten, einen Code schreiben, der C ++ überholt. Darüber hinaus können Sie Ihren eigenen JavaScript-Compiler schreiben, der ein einzelnes Programm kompiliert und die "Pluspunkte" in der Geschwindigkeit überholt. Und dies ist im Prinzip eine gültige Option.
Sozialer Druck eines beliebten Open-Source-Projekts
Mit dem Wachstum und der Popularität von Projekten geht ein gewisses Maß an Verantwortung einher. Aber du hast nicht wirklich Verpflichtungen. Diese Tatsache ist nicht immer leicht zu verstehen, besonders wenn alle möglichen Leute zu GitHub kommen und sagen: „Bei mir funktioniert das hier nicht! Repariere es dringend! Ich brauche das wirklich, um zu arbeiten. Geh und repariere es! " Oder ein Typ bekommt einen Job und ich bin im Urlaub. Drei oder vier Tage vergehen, ich habe nicht einmal gesehen, dass er dort etwas angefangen hat. Ich ruhe mich irgendwo aus und der Typ beginnt - „Warum zum Teufel antwortest du mir nicht? Was für eine Community hat dieses Projekt ?! Sie sind im Allgemeinen alle ekelhafte Menschen, Sie müssen schlechte Dinge mit Ihnen tun! Ich habe meine Zeit verschwendet, dir geschrieben, dass du falsch liegst, und du tust überhaupt nichts dagegen, du hast mich vier Tage lang ignoriert! Wie ist das möglich ?! "
Und je beliebter das Projekt ist, desto mehr sozialer Druck entsteht durch Menschen, die glauben, dass Open Source ein Ort ist, an dem andere Menschen Ihre Arbeit kostenlos für Sie erledigen. Aber eigentlich ist es nicht.
Und jetzt, wenn Immunität gegen Menschen auftritt, die etwas von Ihnen wollen, wird das Leben viel einfacher. Jetzt komme ich zu BenchmarkDorNet, wenn ich Zeit und Stimmung zum Codieren habe. Ich weiß, dass es dort viele Fehler gibt. Sie sind größtenteils unkritisch und betreffen einige Randfälle - in einer solchen Umgebung mit der neuesten Vorschau des fünften DotNet funktioniert irgendwo etwas nicht. Na gut, lass es nicht funktionieren. Wenn ich in der Stimmung bin, werde ich es reparieren.
Wenn andere Leute es brauchen, können sie es selbst reparieren und eine Pull-Anfrage senden - ich werde eine Überprüfung durchführen, wenn ich Zeit und Stimmung habe.
Sehen Sie sich hier den gesamten Podcast an .