{"id":35851,"date":"2019-10-31T22:07:03","date_gmt":"2019-10-31T19:07:03","guid":{"rendered":"https:\/\/prohoster.info\/blog\/bolshoe-intervyu-s-kliffom-klikom-ottsom-jit-kompilyatsii-v-java\/"},"modified":"2019-10-31T22:07:03","modified_gmt":"2019-10-31T19:07:03","slug":"bolshoe-intervyu-s-kliffom-klikom-ottsom-jit-kompilyatsii-v-java","status":"publish","type":"post","link":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/bolshoe-intervyu-s-kliffom-klikom-ottsom-jit-kompilyatsii-v-java","title":{"rendered":"Ein gro\u00dfes Interview mit Cliff Click \u2014 dem Vater der JIT-Kompilierung in Java.","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Ein gro\u00dfes Interview mit Cliff Click \u2014 dem Vater der JIT-Kompilierung in Java.\" src=\"\/wp-content\/uploads\/2019\/07\/9ea9740ef74c0ae14d334482af115222.png\" style=\"display:block;margin: 0 auto;\" \/><strong>Cliff Click<\/strong> \u2014 CTO des Unternehmens Cratus (IoT-Sensoren zur Verbesserung von Prozessen), Gr\u00fcnder und Mitgr\u00fcnder mehrerer Startups (darunter Rocket Realtime School, Neurensic und H2O.ai) mit mehreren erfolgreichen Exits. Cliff schrieb seinen ersten Compiler mit 15 Jahren (Pascal f\u00fcr TRS Z-80)! Er ist am bekanntesten f\u00fcr seine Arbeit an C2 in Java (the Sea of Nodes IR). Dieser Compiler zeigte der Welt, dass JIT hochwertigen Code erzeugen kann, was zu einem der Faktoren f\u00fcr die Etablierung von Java als einer der Hauptplattformen f\u00fcr moderne Software wurde. Sp\u00e4ter half Cliff dem Unternehmen Azul Systems, einen 864-Kern-Mainframe mit Software in reinem Java zu entwickeln, der GC-Pausen auf einem 500-GB-Heap in weniger als 10 Millisekunden unterst\u00fctzte. Insgesamt hat Cliff an allen Aspekten der JVM gearbeitet.<br clear=\"all\"><br \/>\n\u00a0<br \/>\nDieser Hub-Post ist ein gro\u00dfes Interview mit Cliff. Wir werden \u00fcber folgende Themen sprechen:<\/p>\n<p><\/p>\n<ul>\n<li>\u00dcbergang zu niedrigstufigen Optimierungen<\/li>\n<li>Wie man eine gro\u00dfe Refaktorisierung durchf\u00fchrt<\/li>\n<li>Kostenmodell<\/li>\n<li>Lernen von niedrigstufigen Optimierungen<\/li>\n<li>Praktische Beispiele zur Leistungsverbesserung<\/li>\n<li>Warum man seine eigene Programmiersprache erstellen sollte<\/li>\n<li>Karriere als Performance-Ingenieur<\/li>\n<li>Technische Herausforderungen<\/li>\n<li>Ein bisschen \u00fcber Registerzuweisung und Multicore-Verarbeitung<\/li>\n<li>Die gr\u00f6\u00dfte Herausforderung im Leben<\/li>\n<\/ul>\n<p><\/p>\n<p>Das Interview f\u00fchren:<\/p>\n<p><\/p>\n<ul>\n<li><strong>Andrey Sataryan<\/strong> von Amazon Web Services. In seiner Karriere hat er in ganz unterschiedlichen Projekten gearbeitet: Er testete die verteilte NewSQL-Datenbank bei Yandex, ein cloudbasiertes Erkennungssystem im Kaspersky Lab, ein Mehrspieler-Spiel bei Mail.ru und einen Dienst zur Berechnung von W\u00e4hrungswerten bei der Deutschen Bank. Er interessiert sich f\u00fcr das Testen von gro\u00dfangelegten Backend- und verteilten Systemen.<\/li>\n<li><strong>Vladimir Sitnikov<\/strong> von Netcracker. Er arbeitet seit zehn Jahren an der Leistung und Skalierbarkeit von NetCracker OS \u2013 Software, die von Kommunikationsanbietern zur Automatisierung von Netzwerk- und Netzwerkausr\u00fcstungsmanagementprozessen verwendet wird. Er besch\u00e4ftigt sich mit Fragen zur Java-Performance und Oracle Database. Er ist der Autor von mehr als einem Dutzend Leistungsverbesserungen im offiziellen PostgreSQL JDBC-Treiber.<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/li>\n<\/ul>\n<p><\/p>\n<h1 id=\"perehod-k-nizkourovnevym-optimizaciyam\">\u00dcbergang zu niedrigstufigen Optimierungen<\/h1>\n<p><\/p>\n<p><strong>Andrey<\/strong>: Sie sind eine bekannte Pers\u00f6nlichkeit in der Welt der JIT-Compilation, in Java und der Arbeit an Performance im Allgemeinen, richtig?\u00a0<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Das stimmt!<\/p>\n<p><\/p>\n<p><strong>Andrey<\/strong>: Lassen Sie uns mit allgemeinen Fragen zur Arbeitsweise bei der Performance beginnen. Was denken Sie \u00fcber die Wahl zwischen hoch- und niedrigstufigen Optimierungen wie der Arbeit auf Level CPU?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Hier ist alles einfach. Der schnellste Code ist der, der nie ausgef\u00fchrt wird. Daher sollte man immer mit einem hohen Level beginnen und an den Algorithmen arbeiten. Eine bessere O-Notation wird eine schlechtere \u00fcbertreffen, es sei denn, es kommen gro\u00dfe Konstanten ins Spiel. Niedrigstufige Dinge kommen ganz zuletzt. Normalerweise, wenn Sie den gesamten restlichen Stack gut optimiert haben und immer noch etwas Interessantes \u00fcbrig bleibt \u2013 das ist der niedrigste Level. Aber wie f\u00e4ngt man auf hohem Niveau an? Wie erkennt man, dass man genug Arbeit auf hohem Niveau geleistet hat? Nun\u2026 eigentlich nicht. Es gibt keine fertigen Rezepte. Man muss das Problem durchdringen, entscheiden, was man tun will (um keine unn\u00f6tigen Schritte zu machen), und erst dann kann man den Profiler entbl\u00f6\u00dfen, der etwas N\u00fctzliches sagen kann. Irgendwann merkt man selbst, dass man sich von unn\u00f6tigen Dingen befreit hat und es an der Zeit ist, sich mit der Feineinstellung auf niedrigem Niveau zu besch\u00e4ftigen. Das ist definitiv eine besondere Kunstform. Viele Leute erledigen unn\u00f6tige Dinge, bewegen sich aber so schnell, dass sie keine Zeit haben, sich um die Leistung zu k\u00fcmmern. Aber das ist, bis das Thema zur Sprache kommt. In der Regel interessiert es 99% der Zeit niemanden, womit ich besch\u00e4ftigt bin, bis ein wichtiger Aspekt auf dem kritischen Weg auftaucht, der f\u00fcr jemanden von Bedeutung ist. Und dann fangen alle an, dich zu fragen, \u201ewarum es von Anfang an nicht perfekt funktioniert hat\u201c. Im Grunde gibt es immer etwas, das die Leistung verbessern kann. Aber 99% der Zeit hast du keine Anhaltspunkte! Du versuchst einfach, etwas zum Laufen zu bringen und verstehst im Prozess, was wichtig ist. Man kann niemals im Voraus wissen, dass genau dieses St\u00fcck perfekt sein muss, daher muss man im Wesentlichen in allem perfekt sein. Und das ist unm\u00f6glich und so macht man es nicht. Es gibt immer unz\u00e4hlige Dinge zu reparieren \u2013 und das ist ganz normal.<\/p>\n<p><\/p>\n<h1 id=\"kak-delat-bolshoy-refaktoring\">Wie man eine gro\u00dfe Refaktorisierung durchf\u00fchrt<\/h1>\n<p><\/p>\n<p><strong>Andrey<\/strong>: Wie arbeiten Sie an der Leistung? Das ist doch ein durchg\u00e4ngiges Problem. Hatten Sie beispielsweise schon einmal mit Problemen zu tun, die aus der \u00dcberlappung einer gro\u00dfen Menge bereits vorhandener Funktionalit\u00e4t resultieren?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Ich versuche, das zu vermeiden. Wenn ich wei\u00df, dass die Leistung ein Problem werden k\u00f6nnte, denke ich nach, bevor ich mit dem Programmieren beginne, insbesondere \u00fcber Datenstrukturen. Aber oft entdeckt man all das erst viel sp\u00e4ter. Und dann muss man extreme Ma\u00dfnahmen ergreifen und das tun, was ich \u201eschreibe neu und herrsche\u201c nenne: Man muss sich ein ausreichend gro\u00dfes St\u00fcck schnappen. Einen Teil des Codes muss man so oder so neu schreiben, sei es wegen Leistungproblemen oder aus einem anderen Grund. Welcher Grund auch immer f\u00fcr das Neuschreiben des Codes vorliegt, es ist fast immer besser, ein gr\u00f6\u00dferes St\u00fcck neu zu schreiben als ein kleineres St\u00fcck. In diesem Moment fangen alle an zu zittern aus Angst: \u201eOh Gott, man kann so viel Code nicht anfassen!\u201c Aber in der Tat funktioniert dieser Ansatz fast immer viel besser. Man muss sich sofort eines gro\u00dfen Problems annehmen, einen gro\u00dfen Kreis darum ziehen und sagen: Alles, was innerhalb des Kreises ist, schreibe ich neu. Die Grenze ist schlie\u00dflich viel kleiner als der Inhalt, der darin ersetzt werden soll. Und wenn eine solche Grenzziehung die Arbeit darin perfekt macht \u2013 hast du freie Hand, mach, was du willst. Sobald du das Problem verstanden hast, verl\u00e4uft der Neuschreibprozess viel einfacher, also bei\u00dfe in ein gro\u00dfes St\u00fcck!<br \/>\nGleichzeitig, wenn du ein gro\u00dfes St\u00fcck neu schreibst und verstehst, dass die Leistung ein Problem werden k\u00f6nnte, kannst du sofort anfangen, dir dar\u00fcber Gedanken zu machen. Normalerweise wird das zu einfachen Dingen wie \u201eKopiere keine Daten, verwalte Daten so einfach wie m\u00f6glich, mache sie kleiner\u201c. Bei gro\u00dfen Neuschreibungen gibt es Standards zur Verbesserung der Leistung. Diese drehen sich fast immer um die Daten.<\/p>\n<p><\/p>\n<h1 id=\"model-stoimosti\">Kostenmodell<\/h1>\n<p><\/p>\n<p><strong>Andrey<\/strong>: In einem der Podcasts habt ihr \u00fcber Kostenmodelle im Kontext der Leistung gesprochen. K\u00f6nnt ihr erkl\u00e4ren, was damit gemeint war?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Nat\u00fcrlich. Ich wurde in einer Zeit geboren, in der die Prozessorleistung extrem wichtig war. Und diese \u00c4ra kehrt wieder zur\u00fcck \u2013 das Schicksal kennt keinen Mangel an Ironie. Ich begann zu leben, als es noch 8-Bit-Maschinen gab, mein erster Computer arbeitete mit 256 Bytes. Genau, mit Bytes. Alles war sehr klein. Man musste die Anweisungen z\u00e4hlen, und sobald wir anfingen, in die h\u00f6heren Programmiersprachen aufzusteigen, \u00fcbernahmen die Sprachen immer mehr und mehr. Es gab Assembler, dann Basic, dann C, und C \u00fcbernahm die Arbeit mit vielen Details, wie Registerzuweisungen und das Finden von Anweisungen. Aber dort war alles ziemlich klar, und wenn ich einen Zeiger auf eine Instanz einer Variable machte, bekam ich einen Load, und die Kosten f\u00fcr diese Anweisung sind bekannt. Die Hardware liefert eine bekannte Anzahl von Maschinenzyklen, sodass die Ausf\u00fchrungsgeschwindigkeit verschiedener Dinge einfach berechnet werden kann, indem man alle Anweisungen zusammenz\u00e4hlt, die man ausf\u00fchren m\u00f6chte. Jede compare\/test\/branch\/call\/load\/store konnte zusammengez\u00e4hlt werden, und man konnte sagen: hier ist die Ausf\u00fchrungszeit. Wenn man an der Leistungsverbesserung arbeitet, f\u00e4llt einem auf, welche Zahlen mit den kleinen hei\u00dfen Zyklen \u00fcbereinstimmen.\u00a0<br \/>\nAber sobald du auf Java, Python und \u00e4hnliche Dinge umschaltest, entfernst du dich sehr schnell vom Low-Level-Hardware. Wie hoch sind die Kosten f\u00fcr den Aufruf eines Getters in Java? Wenn JIT in HotSpot alles richtig <noindex><a rel=\"nofollow\" href=\"https:\/\/wiki.openjdk.java.net\/display\/HotSpot\/Inlining\">inlined<\/a><\/noindex>, dann wird es ein Load sein, aber wenn er das nicht gemacht hat \u2013 wird es ein Funktionsaufruf sein. Da der Aufruf in einem hei\u00dfen Zyklus liegt, wird er alle anderen Optimierungen in diesem Zyklus zunichte machen. Daher werden die tats\u00e4chlichen Kosten viel h\u00f6her sein. Und du verlierst sofort die F\u00e4higkeit, auf einen Codeabschnitt zu schauen und zu verstehen, dass wir ihn in Bezug auf die Taktfrequenz des Prozessors, den verwendeten Speicher und den Cache ausf\u00fchren sollten. All das wird nur interessant, wenn man wirklich in die Performance eintaucht.<br \/>\nHeute befinden wir uns in einer Situation, in der die Prozessorgeschwindigkeiten seit einem Jahrzehnt kaum gewachsen sind. Die alten Zeiten kehren zur\u00fcck! Sie k\u00f6nnen nicht mehr auf gute einzelne Thread-Leistung z\u00e4hlen. Aber wenn Sie sich zuf\u00e4llig mit paralleler Verarbeitung befassen \u2013 das ist wahnsinnig kompliziert, alle schauen Sie an wie James Bond. Zehnfache Beschleunigungen entstehen hier normalerweise an Stellen, wo jemand etwas verpasst hat. Parallelit\u00e4t erfordert viel Arbeit. Um diese zehnfache Beschleunigung zu erreichen, muss man das Preis-Leistungs-Modell verstehen. Was kostet was. Und dazu muss man verstehen, wie die Sprache auf die zugrunde liegende Hardware abgestimmt ist.<br \/>\nMartin Thompson hat ein passendes Wort f\u00fcr seinen Blog gefunden <noindex><a rel=\"nofollow\" href=\"https:\/\/mechanical-sympathy.blogspot.com\/\">Mechanische Sympathie<\/a><\/noindex>! Man muss verstehen, was die Hardware vorhat, wie genau sie es macht und warum sie \u00fcberhaupt das tut, was sie tut. Mit diesem Wissen ist es ziemlich einfach, die Anweisungen zu z\u00e4hlen und herauszufinden, wo die Ausf\u00fchrungszeit verloren geht. Wenn Sie jedoch nicht die richtige Vorbildung haben, suchen Sie einfach die schwarze Katze im dunklen Raum. Ich sehe st\u00e4ndig Menschen, die die Leistung optimieren, ohne die geringste Ahnung zu haben, was sie eigentlich tun. Sie k\u00e4mpfen sehr und kommen nicht wirklich voran. Und wenn ich denselben Code nehme, ein paar kleine Hacks einf\u00fcge und f\u00fcnf- oder zehnfache Beschleunigung erziele, sagen sie: \u201eNun, das ist nicht fair, wir wussten sowieso, dass du besser bist.\u201c Erstaunlich. Wor\u00fcber rede ich\u2026 das Preis-Leistungs-Modell \u2013 das betrifft, welchen Code man schreibt und wie schnell er im Durchschnitt im Gesamtkontext arbeitet.<\/p>\n<p><\/p>\n<p><strong>Andrey<\/strong>: Und wie h\u00e4lt man so viel im Kopf? Das erreicht man mit viel Erfahrung, oder? Wo bekommt man diese Erfahrung her?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Nun, meine Erfahrung habe ich auf nicht gerade einfache Weise gesammelt. Ich habe noch zu Zeiten in Assembler programmiert, als man jede einzelne Anweisung verstehen konnte. Es mag dumm klingen, aber seitdem ist mir der Befehlssatz des Z80 fest im Ged\u00e4chtnis geblieben. Ich erinnere mich nicht an die Namen von Menschen schon eine Minute nach dem Gespr\u00e4ch, aber ich erinnere mich an den Code, den ich vor 40 Jahren geschrieben habe. Komisch, das sieht aus wie das Syndrom der \"<noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/%D0%A1%D0%B8%D0%BD%D0%B4%D1%80%D0%BE%D0%BC_%D1%81%D0%B0%D0%B2%D0%B0%D0%BD%D1%82%D0%B0\">schlechten Wissenschaftler<\/a><\/noindex>\u00bb.<\/p>\n<p><\/p>\n<h1 id=\"obuchenie-nizkourovnevym-optimizaciyam\">Lernen von niedrigstufigen Optimierungen<\/h1>\n<p><\/p>\n<p><strong>Andrey<\/strong>\": Gibt es einen einfacheren Weg, da reinzukommen?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Ja und nein. Das Metall, das wir alle benutzen, hat sich in dieser Zeit nicht so sehr ver\u00e4ndert. Alle verwenden x86, au\u00dfer Smartphones mit Arm. Wenn du dich nicht mit hartem Embedded Programming besch\u00e4ftigst, hast du alles genau so wie vorher. Gut, weiter. Die Instruktionen haben sich seit Jahrhunderten nicht ge\u00e4ndert. Du musst losgehen und etwas in Assembly schreiben. Ein wenig, aber genug, um zu anfangen, es zu verstehen. Ihr l\u00e4chelt, und ich meine das ganz ernst. Es ist wichtig, das Verh\u00e4ltnis zwischen Sprache und Hardware zu verstehen. Danach musst du versuchen, ein kleines Spielzeug-Compiler f\u00fcr eine kleine Spielzeug-Sprache zu schreiben. \u201eSpielzeug\u201c bedeutet, dass es in einem vern\u00fcnftigen Zeitrahmen gemacht werden muss. Es kann super einfach sein, aber es muss Anweisungen generieren. Der Akt der Generierung von Anweisungen wird helfen, das Kostenmodell f\u00fcr die Br\u00fccke zwischen dem Hochsprachen-Code, an dem alle arbeiten, und dem Maschinencode, der auf der Hardware ausgef\u00fchrt wird, zu verstehen. Diese Beziehung wird sich im Kopf festsetzen, w\u00e4hrend du den Compiler schreibst. Auch bei dem einfachsten Compiler. Danach kannst du anfangen, dir Java anzusehen und feststellen, dass ihr semantischer Abgrund viel tiefer ist, und dass es viel schwieriger ist, Br\u00fccken dar\u00fcber zu bauen. In Java ist es viel schwieriger zu verstehen, ob unsere Br\u00fccke gut oder schlecht ist, was sie zum Einsturz bringt und was nicht. Aber du brauchst einen Ausgangspunkt, wenn du den Code ansiehst und verstehst: \u201eAh, dieser Getter sollte immer inline gesetzt werden.\u201c Und dann stellt sich heraus, dass dies manchmal der Fall ist, au\u00dfer wenn die Methode zu gro\u00df wird und der JIT alles m\u00f6gliche inline setzt. Die Performance solcher Stellen kann man sofort vorhersagen. Normalerweise funktionieren Getter gut, aber dann siehst du dir gro\u00dfe hei\u00dfe Schleifen an und verstehst, dass dort einige Funktionsaufrufe enthalten sind, deren Zweck unklar ist. Das ist das Problem mit der weit verbreiteten Verwendung von Gettern, der Grund, warum sie nicht inline gesetzt werden: Es ist unklar, ob es sich um einen Getter handelt. Wenn du eine super kleine Codebasis hast, kannst du sie einfach auswendig lernen und dann sagen: \u201eDas ist ein Getter, das ist ein Setter.\u201c In einer gro\u00dfen Codebasis hat jede Funktion ihre eigene Geschichte, die im Grunde niemand kennt. Der Profiler sagt, dass wir 24 % der Zeit mit einer bestimmten Schleife verloren haben, und um zu verstehen, was diese Schleife tut, musst du dir jede Funktion darin ansehen. Es ist unm\u00f6glich, das zu verstehen, ohne die Funktion zu studieren, und das verlangsamt den Verst\u00e4ndnisprozess erheblich. Deshalb benutze ich keine Getter und Setter, ich bin auf ein neues Level gekommen!<br \/>\nWoher bekomme ich ein Preis-Modell? Nun, ich kann nat\u00fcrlich etwas lesen... Aber ich denke, der beste Weg ist zu handeln. Ein kleiner Compiler zu erstellen ist der beste Weg, das Preis-Modell zu verstehen und es sich selbst klarzumachen. Ein kleiner Compiler, der sich f\u00fcr das Programmieren einer Mikrowelle eignet \u2013 das ist eine Aufgabe f\u00fcr Anf\u00e4nger. Ich meine, wenn du bereits Programmierkenntnisse hast, sollte es ausreichen. All diese Sachen wie das Parsen einer Zeile, die ein algebraischer Ausdruck sein wird, die Anweisungen der mathematischen Operationen in der richtigen Reihenfolge herauszuziehen, die richtigen Werte aus den Registern zu nehmen \u2013 das alles ist einfach. W\u00e4hrend du das machst, wird es sich in deinem Ged\u00e4chtnis festsetzen. Ich denke, jeder wei\u00df, was ein Compiler macht. Und das wird ein Verst\u00e4ndnis f\u00fcr das Preis-Modell schaffen.<\/p>\n<p><\/p>\n<h1 id=\"prakticheskie-primery-uluchsheniya-proizvoditelnosti\">Praktische Beispiele zur Leistungsverbesserung<\/h1>\n<p><\/p>\n<p><strong>Andrey<\/strong>: Worauf sollte man beim Arbeiten an der Leistungsf\u00e4higkeit noch achten?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Datenstrukturen. \u00dcbrigens, ich habe schon lange keinen Unterricht mehr gegeben... <noindex>Rocket School<\/noindex>. Es machte Spa\u00df, verlangte aber so viel Einsatz, und ich habe schlie\u00dflich auch noch ein Leben! Also, bei einer der gro\u00dfen und interessanten Klassen, \"Wohin geht eure Leistung\", gab ich den Studenten ein Beispiel: Zweieinhalb Gigabyte Fintech-Daten wurden aus einer CSV-Datei gelesen und dann musste die Anzahl der verkauften Produkte berechnet werden. Gew\u00f6hnliche Tick-Marktdaten. UDP-Pakete, die seit den 70er Jahren in ein Textformat umgewandelt wurden. Chicago Mercantile Exchange \u2013 Sachen wie \u00d6l, Mais, Sojabohnen und dergleichen. Man musste diese Produkte z\u00e4hlen, die Anzahl der Transaktionen, das durchschnittliche Volumen der Geld- und Warenbewegungen usw. Das ist ziemlich einfache Handelsmathematik: Den Produktcode finden (das sind 1-2 Zeichen in einer Hash-Tabelle), die Summe erhalten, sie in einen der Satz von Transaktionen hinzuf\u00fcgen, das Volumen, die Kosten und ein paar andere Dinge hinzuf\u00fcgen. Sehr einfache Mathematik. Die Spielzeug-Implementierung war sehr geradlinig: Alles liegt in einer Datei, ich lese die Datei und arbeite mich durch sie, teile die einzelnen Eintr\u00e4ge in Java-Strings auf, suche darin die ben\u00f6tigten Dinge und addiere sie gem\u00e4\u00df der oben beschriebenen Mathematik. Und es funktioniert mit einer gewissen Geschwindigkeit. <\/p>\n<p><\/p>\n<p>Mit diesem Ansatz ist klar, was passiert, und paralleles Rechnen wird hier nicht helfen, richtig? Es stellt sich heraus, dass man durch die Wahl der richtigen Datenstrukturen eine f\u00fcnffache Leistungssteigerung erzielen kann. Das \u00fcberrascht sogar erfahrene Programmierer! In meinem speziellen Fall lag der Fokus darauf, dass man im hei\u00dfen Schleifen keinen Speicher allokieren sollte. Naja, das ist nicht die gesamte Wahrheit, aber insgesamt \u2013 man sollte nicht \u201eeinmal pro X\u201c allokieren, wenn X gro\u00df genug ist. Wenn X zwei und einen halben Gigabyte betr\u00e4gt, sollte man nichts \u201eeinmal f\u00fcr einen Buchstaben\u201c, \u201eeinmal f\u00fcr eine Zeile\u201c oder \u201eeinmal f\u00fcr ein Feld\u201c allokieren, nichts in dieser Art. Genau daf\u00fcr wird die Zeit ben\u00f6tigt. Wie funktioniert das eigentlich? Stellen Sie sich vor, ich mache einen Aufruf <code>String.split()<\/code> oder <code>BufferedReader.readLine()<\/code>. <code>Readline<\/code> macht eine Zeichenkette aus einem Satz von Bytes, die \u00fcber das Netzwerk empfangen werden, einmal f\u00fcr jede Zeile, f\u00fcr jede der Hundert Millionen Zeilen. Ich nehme diese Zeile, analysiere sie und werfe sie weg. Warum ich sie wegwerfe \u2013 nun, ich habe sie bereits verarbeitet, das ist es. Daher wird f\u00fcr jedes Byte, das aus diesen 2.7G gelesen wird, zwei Zeichen in der Zeichenkette geschrieben, das sind bereits 5.4G, und die brauche ich danach nicht mehr, also werden sie weggeworfen. Wenn man sich die Durchsatzleistung des Speichers ansieht, laden wir 2.7G, die durch den Speicher und den Speicherbus in die CPU gehen, und dann werden doppelt so viele in die im Speicher liegende Zeichenkette gesendet, und all das wird beim Erstellen jeder neuen Zeichenkette \u00fcberschrieben. Aber ich muss sie lesen, die Hardware liest sie, selbst wenn danach alles \u00fcberschrieben wird. Und ich muss sie schreiben, weil ich eine Zeichenkette erstellt habe und die Caches \u00fcberlaufen \u2013 der Cache kann nicht 2.7G aufnehmen. Insgesamt lese ich f\u00fcr jedes gelesene Byte noch zwei zus\u00e4tzliche Bytes und schreibe zwei zus\u00e4tzliche Bytes, und am Ende haben wir ein Verh\u00e4ltnis von 4:1 \u2013 mit so einem Verh\u00e4ltnis verschwenden wir ineffizient die Speicherbandbreite. Und dann stellt sich heraus, dass, wenn ich <code>String.split()<\/code> \u2013 das mache, mache ich das bei weitem nicht zum letzten Mal, darin k\u00f6nnen noch 6-7 Felder vorhanden sein. Daher f\u00fchrt der klassische CSV-Lese-Code mit anschlie\u00dfender Zeilenanalyse zu einem Verlust der Speicherbandbreite im Bereich von 14:1 im Vergleich zu dem, was man tats\u00e4chlich gerne h\u00e4tte. Wenn man diese Allokationen eliminiert, kann man eine f\u00fcnfmal schnellere Verarbeitung erreichen. <\/p>\n<p><\/p>\n<p>Und das ist nicht wirklich sehr kompliziert. Wenn man den Code aus dem richtigen Winkel betrachtet, wird alles ziemlich einfach, sobald man das Wesen des Problems erkannt hat. Man sollte \u00fcberhaupt nicht aufh\u00f6ren, Speicher zuzuweisen: Das Problem ist nur, dass man etwas zuweist und es sofort stirbt, wodurch wichtige Ressourcen verbrannt werden, die in diesem Fall \u2013 die Speicherkapazit\u00e4t \u2013 sind. Und das f\u00fchrt zu einem R\u00fcckgang der Leistung. Auf x86 muss man normalerweise aktiv Taktzyklen des Prozessors verbrauchen, hier jedoch hat man den gesamten Speicher viel fr\u00fcher verbrannt. Die L\u00f6sung besteht darin, die Anzahl der Zuweisungen zu reduzieren.\u00a0<br \/>\nEin weiterer Teil des Problems ist, dass, wenn man einen Profiler startet, wenn der Speicherplatz ersch\u00f6pft ist, genau in dem Moment, in dem das passiert, man normalerweise auf die R\u00fcckkehr des Caches wartet, weil er mit M\u00fcll gef\u00fcllt ist, den man gerade erzeugt hat, mit all diesen Zeilen. Daher wird jede Load- oder Store-Operation langsam, da sie zu Cache-Fehlgriffen f\u00fchrt \u2013 der gesamte Cache ist langsam geworden und wartet darauf, dass der M\u00fcll abtransportiert wird. Daher wird der Profiler nur ein warmes zuf\u00e4lliges Rauschen zeigen, das sich \u00fcber den gesamten Zyklus erstreckt \u2013 es wird keine einzelne hei\u00dfe Anweisung oder Stelle im Code geben. Nur Rauschen. Und wenn man sich die GC-Zyklen ansieht, werden sie alle aus der Young Generation stammen und super schnell sein \u2013 Mikrosekunden oder h\u00f6chstens Millisekunden. Denn der gesamte Speicher stirbt sofort. Man weist Milliarden von Gigabyte zu, und er schneidet sie ab, schneidet sie ab und schneidet sie erneut ab. Das alles passiert sehr schnell. Man hat also billige GC-Zyklen, warmes Rauschen \u00fcber den gesamten Zyklus, aber man m\u00f6chte eine 5-fache Beschleunigung erzielen. In diesem Moment sollte in einem der Kopf etwas \u201eWarum ist das so?!\u201c zusammenschlagen. Ein \u00dcberlauf des Speicherbereichs wird im klassischen Debugger nicht angezeigt; man muss den Debugger der Hardware-Leistungsz\u00e4hler starten und es selbst direkt sehen. Und indirekt kann man dies aus diesen drei Symptomen vermuten. Das dritte Symptom ist, wenn man schaut, was man zuweist, den Profiler fragt, und er antwortet: \u201eDu hast eine Milliarde Zeilen erzeugt, aber der GC hat kostenlos gearbeitet.\u201c Sobald das passiert ist, begreift man, dass man zu viele Objekte erzeugt hat und den gesamten Speicher verbrannt hat. Es gibt einen Weg, dies zu kl\u00e4ren, aber er ist nicht offensichtlich.\u00a0<\/p>\n<p><\/p>\n<p>Das Problem liegt in der Datenstruktur: eine blo\u00dfe Struktur, die all dem zugrunde liegt, sie ist zu gro\u00df, sie belegt 2,7 GB auf der Festplatte, daher ist es sehr unerw\u00fcnscht, eine Kopie davon zu erstellen \u2013 man m\u00f6chte sie direkt aus dem Netzwerk-Byte-Puffer in die Register laden, um nicht f\u00fcnfmal hin und her zwischen dort und zur\u00fcck zu lesen oder zu schreiben. Leider stellt Java standardm\u00e4\u00dfig keine solche Bibliothek im JDK zur Verf\u00fcgung. Aber das ist doch trivial, oder? Im Grunde sind das 5-10 Zeilen Code, die f\u00fcr die Implementierung eines eigenen gepufferten Zeilenladers ben\u00f6tigt werden, der das Verhalten der String-Klasse nachahmt, w\u00e4hrend er gleichzeitig eine Wrapper um den darunterliegenden Byte-Puffer bildet. Infolgedessen scheint es, dass man fast mit Strings arbeitet, tats\u00e4chlich jedoch bewegen sich die Zeiger im Puffer, und rohe Bytes werden nirgendwo kopiert, wodurch immer wieder dieselben Puffer wiederverwendet werden und das Betriebssystem gerne die Dinge \u00fcbernimmt, f\u00fcr die es vorgesehen ist, wie die versteckte doppelte Pufferung dieser Byte-Puffer, sodass man selbst nicht mehr einen endlosen Strom unn\u00f6tiger Daten verarbeitet. \u00dcbrigens, Sie verstehen doch, dass beim Arbeiten mit GC garantiert wird, dass jede Speicherzuweisung nach dem letzten GC-Zyklus nicht mehr vom Prozessor gesehen wird? Daher kann all dies nicht im Cache sein, und was darauf folgt, ist ein 100%-garantierter Fehlschlag. Wenn man mit einem Zeiger arbeitet, dauert es auf x86 1-2 Takte, um ein Register aus dem Speicher zu lesen, und sobald das passiert, bezahlt man, bezahlt man, bezahlt man, denn der gesamte Speicher ist in <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Cache_inclusion_policy\">NINE Caches<\/a><\/noindex> \u2013 und das ist die Kosten f\u00fcr die Speicherzuweisung. Die wahre Kosten.<\/p>\n<p><\/p>\n<p>Mit anderen Worten, Datenstrukturen sind das, was am schwierigsten zu \u00e4ndern ist. Und sobald Sie erkennen, dass Sie die falsche Datenstruktur gew\u00e4hlt haben, die sp\u00e4ter die Leistung beeintr\u00e4chtigen wird, ist in der Regel erheblicher Aufwand erforderlich, aber wenn Sie das nicht tun, wird es sp\u00e4ter schlimmer. Zun\u00e4chst sollten Sie \u00fcber Datenstrukturen nachdenken, das ist wichtig. Die Hauptkosten hier liegen bei den komplexen Datenstrukturen, die oft im Stil \"Ich habe die Datenstruktur X in die Datenstruktur Y kopiert, weil mir Y optisch besser gef\u00e4llt\" verwendet werden. Aber die Kopieroperation (die kosteng\u00fcnstig erscheint) verbraucht tats\u00e4chlich Speicherbandbreite, und hier liegt alles verlorene Rechenzeit begraben. Wenn ich eine riesige Zeichenkette mit JSON habe und sie in einen strukturierten DOM-Baum von POJO oder etwas \u00c4hnlichem umwandeln m\u00f6chte, wird die Parsing-Operation dieser Zeichenkette und die Erstellung von POJO, gefolgt von einem weiteren Zugriff auf das POJO, zus\u00e4tzliche Kosten verursachen \u2013 das ist nicht billig. Es sei denn, Sie greifen viel h\u00e4ufiger auf das POJO zu als auf die Zeichenkette. Alternativ k\u00f6nnte man auch versuchen, die Zeichenkette zu entschl\u00fcsseln und nur das N\u00f6tigste herauszuziehen, ohne sie in POJO umzuwandeln. Wenn das alles auf einem Weg geschieht, der maximale Leistung erfordert, gibt es keine POJO \u2013 man muss direkt in der Zeichenkette arbeiten.<\/p>\n<p><\/p>\n<h1 id=\"zachem-sozdavat-svoy-yazyk-programmirovaniya\">Warum man seine eigene Programmiersprache erstellen sollte<\/h1>\n<p><\/p>\n<p><strong>Andrey<\/strong>: Sie haben gesagt, dass Sie f\u00fcr das Verst\u00e4ndnis des Kostenmodells eine eigene kleine Sprache schreiben m\u00fcssen\u2026<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Nicht eine Sprache, sondern einen Compiler. Sprache und Compiler sind verschiedene Dinge. Der gr\u00f6\u00dfte Unterschied liegt im eigenen Kopf.\u00a0<\/p>\n<p><\/p>\n<p><strong>Andrey<\/strong>: \u00dcbrigens, soweit ich wei\u00df, experimentieren Sie mit dem Erstellen eigener Sprachen. Warum?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Weil ich kann! Ich bin zur H\u00e4lfte im Ruhestand, also ist das mein Hobby. Mein ganzes Leben lang habe ich die Sprachen anderer Leute umgesetzt. Au\u00dferdem habe ich viel an der Codierstilistik gearbeitet. Und auch, weil ich Probleme in anderen Sprachen sehe. Ich sehe, dass es bessere Wege gibt, um allt\u00e4gliche Dinge zu tun. Und ich w\u00fcrde sie nutzen. Ich habe einfach die Nase voll, die Probleme in mir, in Java, in Python und in jeder anderen Sprache zu sehen. Momentan schreibe ich in React Native, JavaScript und Elm als Hobby, das nichts mit dem Ruhestand zu tun hat, sondern mit aktiver Arbeit. Ich schreibe auch in Python und werde wahrscheinlich weiterhin an maschinellem Lernen f\u00fcr Java-Backends arbeiten. Es gibt viele beliebte Sprachen und jede hat interessante Besonderheiten. Jede ist in ihrem eigenen Bereich gut und man kann versuchen, all diese Features zu vereinen. Also besch\u00e4ftige ich mich mit dem Lernen interessanter Dinge f\u00fcr mich, dem Verhalten der Sprache, und versuche, eine sinnvolle Semantik zu erfinden. Und bisher gelingt es mir gut! Momentan k\u00e4mpfe ich mit der Semantik des Speichers, weil ich sie wie in C und Java haben m\u00f6chte und ein starkes Speicher-Modell sowie eine Semantik f\u00fcr Loads und Stores bekommen m\u00f6chte. Dabei will ich eine automatische Typableitung wie in Haskell haben. Hier, ich versuche, eine Haskell-\u00e4hnliche Typableitung mit Speicher zu mischen, der wie in C und Java funktioniert. Damit besch\u00e4ftige ich mich seit 2-3 Monaten, zum Beispiel.<\/p>\n<p><\/p>\n<p><strong>Andrey<\/strong>: Wenn Sie eine Sprache erstellen, die die besten Aspekte anderer Sprachen \u00fcbernimmt, haben Sie dar\u00fcber nachgedacht, dass jemand das Gegenteil macht: Ihre Ideen nimmt und sie bei sich selbst einsetzt?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Genau so entstehen neue Sprachen! Warum \u00e4hnelt Java C? Weil C eine gute Syntax hatte, die jeder verstand, und Java sich von dieser Syntax inspirieren lie\u00df, um Typsicherheit, Array-Grenzkontrollen, GC hinzuzuf\u00fcgen und einige Dinge aus C zu verbessern. Sie haben ihre eigenen hinzugef\u00fcgt. Aber sie haben sich stark inspirieren lassen, oder? Alle stehen auf den Schultern von Riesen, die vor einem waren \u2013 so funktioniert der Fortschritt.<\/p>\n<p><\/p>\n<p><strong>Andrey<\/strong>: Soweit ich verstehe, wird Ihre Sprache sicher im Umgang mit dem Speicher sein. Haben Sie dar\u00fcber nachgedacht, etwas wie den Borrow Checker aus Rust zu implementieren? Haben Sie ihn angesehen, wie gef\u00e4llt er Ihnen?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Also, ich programmiere schon eine Ewigkeit in C, mit all diesen malloc und free, und verwalte die Lebensdauer manuell. Wissen Sie, 90-95% der manuell verwalteten Lebensdauer haben die gleiche Struktur. Und es ist sehr, sehr m\u00fchsam, das von Hand zu machen. Ich w\u00fcnschte, der Compiler w\u00fcrde einfach sagen, was da passiert und was Sie mit Ihren Aktionen erreicht haben. F\u00fcr gewisse Dinge macht der Borrow Checker das standardm\u00e4\u00dfig. Au\u00dferdem sollte er automatisch Informationen ableiten, alles verstehen und mich nicht mit der Notwendigkeit belasten, dieses Verst\u00e4ndnis zu formulieren. Er sollte mindestens eine lokale Escape-Analyse durchf\u00fchren, und nur wenn das nicht funktioniert, sollten Typanmerkungen hinzugef\u00fcgt werden, die die Lebensdauer beschreiben \u2013 und ein solches Schema ist viel komplizierter als der Borrow Checker oder \u00fcberhaupt jeder existierende Speicherpr\u00fcfer. Die Wahl zwischen \u201ealles in Ordnung\u201c und \u201eich habe nichts verstanden\u201c \u2013 nein, es sollte etwas Besseres geben.\u00a0<br \/>\nAls jemand, der viel Code in C geschrieben hat, halte ich die Unterst\u00fctzung von automatischer Speicherverwaltung f\u00fcr eine der wichtigsten Dinge. Zudem st\u00f6rt mich, wie viel Speicher Java verbraucht, und die gr\u00f6\u00dfte Beschwerde betrifft den GC. Bei der Speicherzuweisung in Java erh\u00e4ltst du den Speicher, der im letzten GC-Zyklus lokal war, nicht zur\u00fcck. In Sprachen mit pr\u00e4ziserer Speicherverwaltung ist das anders. Wenn du malloc aufrufst, erh\u00e4ltst du sofort Speicher, der normalerweise gerade verwendet wurde. Meistens machst du mit dem Speicher tempor\u00e4re Dinge und gibst ihn sofort zur\u00fcck. Und er geht sofort in den malloc-Pool zur\u00fcck, und der n\u00e4chste malloc-Zyklus zieht ihn wieder heraus. Deshalb reduziert sich die tats\u00e4chliche Speichernutzung auf die Menge der lebenden Objekte zu einem bestimmten Zeitpunkt plus Lecks. Und wenn du nicht v\u00f6llig unangemessen leckst, bleibt der gr\u00f6\u00dfte Teil des Speichers in Caches und Prozessoren, und das funktioniert schnell. Aber es erfordert viel manuelle Speicherverwaltung mit malloc und free, die in der richtigen Reihenfolge und am richtigen Ort aufgerufen werden m\u00fcssen. Rust kann das eigenst\u00e4ndig gut bew\u00e4ltigen und in vielen F\u00e4llen sogar eine h\u00f6here Leistung bieten, da der Speicherverbrauch nur auf die aktuellen Berechnungen beschr\u00e4nkt ist \u2013 im Gegensatz zur Erwartung des n\u00e4chsten GC-Zyklus, der Speicher freigibt. Am Ende haben wir einen sehr interessanten Weg gefunden, die Leistung zu steigern. Und ziemlich leistungsstark \u2013 ich habe mich mit solchen Sachen bei der Datenverarbeitung f\u00fcr Fintech besch\u00e4ftigt, und das konnte eine Beschleunigung um das F\u00fcnffache bringen. Das ist eine erhebliche Beschleunigung, besonders in einer Welt, in der die Prozessoren nicht schneller werden und wir weiterhin auf Verbesserungen warten.<\/p>\n<p><\/p>\n<h1 id=\"karera-performans-inzhenera\">Karriere als Performance-Ingenieur<\/h1>\n<p><\/p>\n<p><strong>Andrey<\/strong>: Ich w\u00fcrde auch gerne allgemein zur Karriere fragen. Sie wurden ber\u00fchmt durch Ihre Arbeit an JIT in HotSpot, und sind dann zu Azul gewechselt \u2013 das ist auch ein JVM-Unternehmen. Aber dort haben Sie sich mehr mit Hardware als mit Software besch\u00e4ftigt. Und dann haben Sie pl\u00f6tzlich auf Big Data und Machine Learning umgeschaltet, und sp\u00e4ter auf Betrugserkennung. Wie ist das passiert? Das sind sehr unterschiedliche Entwicklungsbereiche.<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Ich besch\u00e4ftige mich schon seit geraumer Zeit mit Programmierung und konnte mich in sehr unterschiedlichen Bereichen auszeichnen. Und wenn die Leute sagen: \u201eOh, du bist der, der JIT f\u00fcr Java gemacht hat!\u201c, ist das immer am\u00fcsant. Dabei habe ich zuvor an einem Klon von PostScript gearbeitet \u2013 jener Sprache, die Apple einst f\u00fcr seine Laserdrucker verwendet hat. Davor habe ich eine Implementierung der Sprache Forth entwickelt. Ich denke, das gemeinsame Thema f\u00fcr mich ist die Entwicklung von Werkzeugen. Mein ganzes Leben lang habe ich Werkzeuge geschaffen, mit denen andere Menschen ihre coolen Programme schreiben. Aber ich habe mich auch mit der Entwicklung von Betriebssystemen, Treibern, Kernel-Debuggern und Programmiersprachen f\u00fcr die Entwicklung von Betriebssystemen befasst, die anf\u00e4nglich trivial waren, aber im Laufe der Zeit immer komplizierter wurden. Aber das Hauptthema bleibt die Entwicklung von Werkzeugen. Ein gro\u00dfer Teil meines Lebens lag zwischen Azul und Sun, und es ging um Java. Doch als ich mich mit Big Data und Machine Learning besch\u00e4ftigte, setzte ich wieder meinen feierlichen Hut auf und sagte: \u201eOh, jetzt haben wir ein nicht triviales Problem, und hier passiert eine Menge interessanter Dinge und es gibt Menschen, die etwas tun.\u201c Es ist ein gro\u00dfartiger Weg f\u00fcr die Entwicklung, den es wert ist, beschritten zu werden. <\/p>\n<p><\/p>\n<p>Ja, ich liebe verteilte Berechnungen sehr. Mein erster Job war w\u00e4hrend des Studiums in C, an einem Werbeprojekt. Es handelte sich um verteilte Berechnungen auf Zilog Z80-Chips, die Daten f\u00fcr eine analoge optische Texterkennung sammelten, die von einem echten analogen Analysator durchgef\u00fchrt wurde. Das war ein cooles und absolut verr\u00fccktes Thema. Aber es gab Probleme, ein Teil wurde nicht richtig erkannt, weshalb das Bild herausgeholt und einer Person gezeigt werden musste, die es bereits mit den Augen gelesen hatte und mitteilte, was dort gesagt wird. Daher gab es Jobs mit Daten, und diese Jobs hatten ihre eigene Sprache. Es gab ein Backend, das all dies bearbeitete \u2013 parallel laufende Z80 mit aktiven vt100-Terminals \u2013 jeweils eines pro Person, und es gab ein Modell f\u00fcr parallele Programmierung auf Z80. Ein gewisser gemeinsamer Speicherbereich, den alle Z80 innerhalb einer Sternkonfiguration teilten; auch das Backplane wurde geteilt, und die H\u00e4lfte des RAM wurde innerhalb des Netzwerks geteilt, w\u00e4hrend die andere H\u00e4lfte privat war oder f\u00fcr etwas anderes verwendet wurde. Eine sinnvoll komplexe parallele verteilte Systemarchitektur mit geteilter... teilweise geteilter Speicher. Wann das war... Ich kann mich schon nicht mehr erinnern, irgendwo in den 80ern. Das ist schon eine Weile her.\u00a0<br \/>\nJa, lassen Sie uns sagen, dass 30 Jahre eine ganz sch\u00f6n lange Zeit ist. Die Herausforderungen, die mit verteilten Berechnungen verbunden sind, gibt es schon seit geraumer Zeit, die Menschen k\u00e4mpfen seit langem mit <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/Beowulf_(%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80)\">Beowulf<\/a><\/noindex>-Clustern. Solche Cluster sehen aus wie\u2026 Zum Beispiel: Es gibt Ethernet und dein schneller x86 ist mit diesem Ethernet verbunden, und jetzt m\u00f6chtest du einen fake shared memory haben, denn damals konnte niemand sich mit dem Codieren von verteilten Berechnungen auseinandersetzen, das war viel zu kompliziert, und deshalb gab es den fake shared memory mit Seitenschutz im Speicher auf x86. Wenn du in diese Seite geschrieben hast, haben wir den anderen Prozessoren gesagt, dass, wenn sie auf denselben shared memory zugreifen wollten, sie das von dir neu laden m\u00fcssen. So entstand eine Art Protokoll zur Unterst\u00fctzung der Koh\u00e4renz von Caches und die Software daf\u00fcr. Ein interessantes Konzept. Das eigentliche Problem lag nat\u00fcrlich woanders. Das Ganze funktionierte, aber du hattest schnell Performance-Probleme, denn niemand verstand das Leistungsmodell auf einem ausreichend guten Niveau \u2013 welche Zugriffsarten auf den Speicher es gab, wie man verhindern kann, dass die Knoten sich endlos gegenseitig pingen und so weiter. <\/p>\n<p><\/p>\n<p>In H2O habe ich mir folgendes \u00fcberlegt: Die Entwickler sind selbst daf\u00fcr verantwortlich, wo Parallelit\u00e4t versteckt ist und wo nicht. Ich habe ein Kodierungsmodell entwickelt, das es einfach und unkompliziert macht, leistungsstarken Code zu schreiben. Langsame Codes zu schreiben, ist dagegen schwierig \u2013 sie werden schlecht aussehen. Man muss sich ernsthaft anstrengen, um langsamen Code zu schreiben, man muss unkonventionelle Methoden einsetzen. Bremsender Code ist sofort sichtbar. Folglich wird normalerweise schneller Code geschrieben, aber man muss herausfinden, was zu tun ist, wenn es um gemeinsamen Speicher geht. Das Ganze h\u00e4ngt von gro\u00dfen Arrays ab, und das Verhalten dort \u00e4hnelt nicht-volatilen gro\u00dfen Arrays in parallelem Java. Stellen Sie sich vor, dass zwei Threads in ein paralleles Array schreiben, einer von ihnen gewinnt, der andere verliert und man nicht wei\u00df, wer wer ist. Wenn sie nicht volatil sind, kann die Reihenfolge beliebig sein \u2013 und das funktioniert wirklich gut. Die Menschen k\u00fcmmern sich um die Reihenfolge der Operationen, setzen volatile richtig ein und erwarten an den richtigen Stellen Probleme mit der Leistung, die mit dem Speicher zusammenh\u00e4ngen. Andernfalls w\u00fcrden sie einfach Code in Form von Schleifen von 1 bis N schreiben, wobei N einige Billionen sind, in der Hoffnung, dass alle komplexen F\u00e4lle automatisch parallel werden \u2013 und dort funktioniert es nicht. Aber in H2O ist es weder Java noch Scala, man kann es als \u201eJava minus minus\u201c betrachten, wenn man m\u00f6chte. Das ist ein sehr verst\u00e4ndlicher Programmierstil und \u00e4hnelt dem Schreiben von einfachem Code in C oder Java mit Schleifen und Arrays. Gleichzeitig kann man den Speicher mit Terabytes verarbeiten. Ich verwende immer noch H2O. Gelegentlich setze ich es in verschiedenen Projekten ein \u2013 und es ist immer noch das schnellste Tool, das die Konkurrenz um ein Vielfaches \u00fcbertrifft. Wenn Sie Big Data mit Spalten-Daten machen, ist es sehr schwierig, H2O zu \u00fcbertreffen.<\/p>\n<p><\/p>\n<h1 id=\"tehnicheskie-chellenzhi\">Technische Herausforderungen<\/h1>\n<p><\/p>\n<p><strong>Andrey<\/strong>: Was war die gr\u00f6\u00dfte Herausforderung in Ihrer gesamten Karriere?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Diskutieren wir den technischen oder den nicht-technischen Teil der Frage? Ich w\u00fcrde sagen, die gr\u00f6\u00dften Herausforderungen sind nicht technischer Natur.\u00a0<br \/>\nWas die technischen Herausforderungen betrifft. Ich habe sie einfach \u00fcberwunden. Ich wei\u00df nicht einmal, was das gr\u00f6\u00dfte war, aber es gab einige ziemlich interessante, die viel Zeit und mentale Anstrengung in Anspruch genommen haben. Als ich zu Sun ging, war ich \u00fcberzeugt, dass ich einen schnellen Compiler entwickeln w\u00fcrde, und eine Menge Seniore sagten mir, dass ich das nie schaffen w\u00fcrde. Aber ich bin diesen Weg gegangen, habe einen Compiler entwickelt, bis hin zum Register-Allocator, und zwar ziemlich schnell. Er war so schnell wie das moderne C1, aber damals war der Allocator viel langsamer, und r\u00fcckblickend war das ein Problem der gro\u00dfen Datenstruktur. Ich brauchte sie, um einen grafischen Register-Allocator zu schreiben, und ich verstand das Dilemma zwischen Ausdrucksst\u00e4rke des Codes und Geschwindigkeit, das in dieser Zeit existierte und sehr wichtig war. Es stellte sich heraus, dass die Datenstruktur normalerweise die Cache-Gr\u00f6\u00dfe der damaligen x86-Architektur \u00fcberschreitet, und daher, wenn ich urspr\u00fcnglich annahm, dass der Register-Allocator 5-10 Prozent der gesamten Just-in-time-Kompilierung ausmachen w\u00fcrde, stellte sich in der Realit\u00e4t heraus, dass es 50 Prozent waren. <\/p>\n<p><\/p>\n<p>Die Zeit verging, der Compiler wurde immer klarer und leistungsf\u00e4higer, h\u00f6rte auf, in einer gr\u00f6\u00dferen Anzahl von F\u00e4llen schlechten Code zu generieren, und die Leistung kam immer n\u00e4her an das, was ein C-Compiler liefert. Es sei denn, du schreibst nat\u00fcrlich einen solchen Schrott, den auch C nicht beschleunigen kann. Wenn du Code wie in C schreibst, bekommst du in einer gr\u00f6\u00dferen Anzahl von F\u00e4llen auch die Leistung wie in C. Und je weiter es ging, desto \u00f6fter entstand Code, der asymptotisch auf dem Niveau von C lag, und der Register-Allocator begann, etwas Vollendetes zu werden \u2026 unabh\u00e4ngig davon, ob dein Code schnell oder langsam lief. Ich arbeitete weiterhin am Allocator, um bessere Zuweisungen zu machen. Er wurde immer langsamer, lieferte aber immer bessere Leistungen in den F\u00e4llen, in denen niemand mehr klarkam. Ich konnte in den Register-Allocator eintauchen, dort einen Monat Arbeit investieren, und pl\u00f6tzlich begann der gesamte Code 5% schneller zu laufen. Das geschah immer wieder, und der Register-Allocator wurde so etwas wie ein Kunstwerk \u2013 alle mochten oder hassten ihn, und die Leute von der Akademie stellten Fragen wie \u201eWarum wird das alles so gemacht?\u201c <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Register_allocation#Linear_Scan\">lineares Scannen<\/a><\/noindex>, und was ist der Unterschied. Die Antwort bleibt die gleiche: der Allokator, der auf Graphf\u00e4rbung basiert, plus sehr sorgf\u00e4ltige Arbeit mit dem Puffer-Code ergibt ein Werkzeug des Sieges, die beste Kombination, die niemand schlagen kann. Und das ist eine ziemlich unauff\u00e4llige Sache. Alles andere, was der Compiler dort macht, sind relativ gut erforschte Dinge, die jedoch ebenfalls auf ein Kunstniveau gebracht wurden. Ich habe immer Dinge gemacht, die den Compiler in ein Kunstwerk verwandeln sollten. Aber nichts davon war au\u00dfergew\u00f6hnlich \u2013 mit Ausnahme des Register-Allokators. Der Trick ist, dass man sorgf\u00e4ltig <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Register_allocation\">abschneiden<\/a><\/noindex> muss, und wenn das passiert (ich kann das n\u00e4her erkl\u00e4ren, wenn es interessiert), bedeutet das, dass man aggressiver inlinieren kann, ohne das Risiko einzugehen, \u00fcber den Knick der Leistungskurve hinauszuschie\u00dfen. Damals gab es viele vollwertige Compiler, die mit Spielereien und Schnickschnack ausgestattet waren und Register-Allokatoren enthielten, aber niemand konnte das so wie ich tun. <\/p>\n<p><\/p>\n<p>Das Problem ist, dass, wenn man Methoden hinzuf\u00fcgt, die inline gehen sollen, und den Bereich des Inlinings immer weiter vergr\u00f6\u00dfert, der Satz der verwendeten Werte die Anzahl der Register sofort \u00fcbersteigt und man ausgelagert werden muss. Der kritische Punkt tritt normalerweise ein, wenn der Allokator nachgibt, und ein guter Kandidat f\u00fcr das Auslagern steht im Vergleich zu einem anderen, sodass man pl\u00f6tzlich wilde Dinge auslagert. Der Nutzen des Inlinings liegt darin, dass man einen Teil des Overheads, den Overhead f\u00fcr den Aufruf und die Speicherung, verliert; man kann die Werte innerhalb des Codes sehen und man kann sie weiter optimieren. Die Kosten des Inlinings bestehen darin, dass eine gro\u00dfe Anzahl lebender Werte entsteht, und wenn dein Register-Allokator mehr auslagert, als n\u00f6tig ist, verlierst du sofort. Daher haben die meisten Allokatoren das Problem, dass, wenn das Inlining einen bestimmten Punkt \u00fcberschreitet, alles auf der Welt ausgelagert wird und die Leistung in den M\u00fclleimer gesp\u00fclt werden kann. Die Compilerentwickler f\u00fcgen einige Heuristiken hinzu: zum Beispiel das Inlining ab einer bestimmten, ausreichend gro\u00dfen Gr\u00f6\u00dfe zu stoppen, da die Allokationen alles verderben. So entsteht ein Bruch im Leistungsdiagramm \u2013 du inline, inline, die Leistung steigt allm\u00e4hlich \u2013 und dann bam! \u2013 f\u00e4llt sie pl\u00f6tzlich steil ab, weil du zu viel inlined. So hat es bis zur Einf\u00fchrung von Java funktioniert. Java erfordert viel mehr Inlining, deshalb musste ich meinen Allokator viel aggressiver gestalten, damit er sich stabilisiert und nicht abst\u00fcrzt; und wenn du zu viel inlined, beginnt er auszulagern, aber irgendwann kommt dennoch der Moment, an dem es hei\u00dft: \u201eKein Auslagern mehr\u201c. Das ist eine interessante Beobachtung und sie ist mir irgendwie auf die Idee gekommen; nicht offensichtlich, aber gut rentabel. Ich habe mich auf aggressives Inlining eingelassen und das hat mich an Stellen gef\u00fchrt, wo die Leistung von Java und C gleichauf ist. Sie sind tats\u00e4chlich sehr nah beieinander \u2013 ich kann Java-Code schreiben, der deutlich schneller ist als C-Code und so weiter, aber insgesamt, im gro\u00dfen Bild der Dinge, sind sie ungef\u00e4hr vergleichbar. Ich denke, ein Teil des Verdienstes liegt beim Register-Allokator, der es mir erlaubt, so dumm wie m\u00f6glich zu inlinen. Ich inline einfach alles, was ich sehe. Die Frage ist, ob der Allokator gut funktioniert und ob der resultierende Code sinnvoll arbeitet. Das war eine gro\u00dfe Herausforderung: das alles zu verstehen und zum Laufen zu bringen.<\/p>\n<p><\/p>\n<h1 id=\"nemnogo-pro-allokaciyu-registrov-i-mnogoyadernost\">Ein bisschen \u00fcber Registerzuweisung und Multicore-Verarbeitung<\/h1>\n<p><\/p>\n<p><strong>Wladimir<\/strong>: Probleme wie die Registerallokation scheinen ein ewiges Thema zu sein. Interessiert es, ob irgendeine Idee vielversprechend war und dann in der Praxis gescheitert ist?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Nat\u00fcrlich! Die Registerallokation ist ein Bereich, in dem du versuchst, einige Heuristiken zu finden, um ein NP-vollst\u00e4ndiges Problem zu l\u00f6sen. Und du wirst niemals in der Lage sein, eine perfekte L\u00f6sung zu erreichen, richtig? Das ist einfach unm\u00f6glich. Schau mal, die Ahead of Time-Kompilierung funktioniert auch schlecht. Es geht hier um Durchschnittsf\u00e4lle. Um typisches Leistungsverm\u00f6gen, so dass du etwas messen kannst, das du f\u00fcr eine gute typische Leistung h\u00e4ltst \u2013 schlie\u00dflich arbeitest du ja daran, sie zu verbessern! Die Registerallokation ist ein Thema, das ganz der Leistung gewidmet ist. Sobald du den ersten Prototyp hast, der funktioniert und das Notwendige macht, kommt die Arbeit an der Performance. Du musst lernen, gut zu messen. Warum ist das wichtig? Wenn es klare Daten gibt, kannst du dir verschiedene Bereiche ansehen und sehen: Aha, das hat hier geholfen, aber dort ist alles kaputtgegangen! Es kommen einige gute Ideen auf, du f\u00fcgst eine neue Heuristik hinzu und pl\u00f6tzlich funktioniert alles im Durchschnitt ein wenig besser. Oder es funktioniert nicht. Ich hatte viele F\u00e4lle, in denen wir um f\u00fcnf Prozent Leistung gek\u00e4mpft haben, die unsere Entwicklung vom vorherigen Allokator unterschieden haben. Und jedes Mal sieht es \u0442\u0430\u043a aus: Irgendwo gewonnen, irgendwo verloren. Wenn du gute Performance-Analysetools hast, kannst du die verlierenden Ideen finden und verstehen, warum sie verlieren. Vielleicht sollte man alles so lassen, wie es ist, oder vielleicht ernsthaft in die Feinabstimmung investieren, oder vielleicht etwas anderes reparieren. Das ist ein ganzes Set von Dingen! Ich habe diesen coolen Hack gemacht, aber ich brauche auch diesen, und diesen, und diesen \u2013 und die kombinierte Summe bringt einige Verbesserungen. Einzelaktionen k\u00f6nnen scheitern. So ist die Natur der Arbeit an der Leistung NP-vollst\u00e4ndiger Probleme.<\/p>\n<p><\/p>\n<p><strong>Wladimir<\/strong>: Es entsteht der Eindruck, dass Dinge wie das F\u00e4rben in Allokatoren bereits gel\u00f6st sind. Nun, f\u00fcr euch gel\u00f6st, judging by what you say, should it be\u2026<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Sie ist nicht als solche gel\u00f6st. Du musst sie in eine \u201egel\u00f6ste\u201c verwandeln. Es gibt schwierige Aufgaben, die gel\u00f6st werden m\u00fcssen. Wenn dies erledigt ist, kommt die Zeit, sich mit der Leistung zu befassen. Du solltest diese Arbeit entsprechend angehen \u2013 Benchmarks durchf\u00fchren, Metriken sammeln, Situationen erkl\u00e4ren, in denen dein alter Hack wieder funktioniert hat (oder umgekehrt, aufgeh\u00f6rt hat zu funktionieren), wenn du zu einer fr\u00fcheren Version zur\u00fcckgehst. Und nicht aufgeben, bis du etwas erreicht hast. Wie ich bereits gesagt habe, wenn es coole Ideen gibt, die nicht funktioniert haben, gibt es im Bereich der Registerallokierung praktisch unendlich viele Ideen. Man k\u00f6nnte zum Beispiel wissenschaftliche Ver\u00f6ffentlichungen lesen. Obwohl dieses Gebiet sich jetzt langsamer entwickelt und klarer ist als in seiner Jugend. Dennoch arbeiten in diesem Bereich unz\u00e4hlige Menschen, und all ihre Ideen sollten ausprobiert werden, sie warten alle auf ihre Chance. Und du kannst nicht sagen, wie gut sie sind, wenn du es nicht ausprobierst. Wie gut sie sich mit allem anderen in deinem Allocator integrieren, denn der Allocator macht viele Dinge, und einige Ideen funktionieren in deinem speziellen Allocator nicht, w\u00e4hrend sie in einem anderen Allocator problemlos funktionieren k\u00f6nnen. Der Hauptweg zum Sieg f\u00fcr den Allocator besteht darin, langsame Dinge vom Hauptweg zu entfernen und gezwungenen Split nach den Grenzen langsamer Wege zu machen. Deshalb, wenn du GC starten willst, den langsamen Weg gehen, deoptimieren, eine Ausnahme werfen, all solche Sachen \u2013 du wei\u00dft, dass diese Dinge relativ selten sind. Und sie sind wirklich selten, das habe ich \u00fcberpr\u00fcft. Du machst zus\u00e4tzliche Arbeit und dadurch verschwinden viele Einschr\u00e4nkungen auf diesen langsamen Wegen, aber das ist nicht sehr wichtig, denn sie sind langsam und werden selten genutzt. Zum Beispiel ein Nullzeiger \u2013 er tritt nie auf, oder? Man muss mehrere Wege f\u00fcr verschiedene Dinge haben, aber sie sollten sich nicht im Hauptweg st\u00f6ren.\u00a0<\/p>\n<p><\/p>\n<p><strong>Wladimir<\/strong>: Was denkst du \u00fcber Mehrkernigkeit, wenn es Tausende von Kernen gibt? Ist das eine n\u00fctzliche Sache?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Der Erfolg von GPUs zeigt, dass es ziemlich n\u00fctzlich ist!<\/p>\n<p><\/p>\n<p><strong>Wladimir<\/strong>: Sie sind ziemlich spezialisiert. Und wie w\u00e4re es mit Allzweckprozessoren?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Nun, das war das Gesch\u00e4ftsmodell von Azul. Die Antwort kam noch aus einer \u00c4ra, in der die Menschen sehr an vorhersehbarer Leistung interessiert waren. Damals war es schwierig, parallelen Code zu schreiben. Das H2O-Codierungsmodell l\u00e4sst sich gut skalieren, ist aber kein universelles Modell. Es ist nur geringf\u00fcgig allgemeiner als die Verwendung von GPU. Sprechen wir \u00fcber die Komplexit\u00e4t der Entwicklung einer solchen Sache oder die Komplexit\u00e4t ihrer Nutzung? Zum Beispiel hat mir Azul eine interessante Lektion erteilt, die nicht ganz offensichtlich ist: kleine Caches sind in Ordnung.\u00a0<\/p>\n<p><\/p>\n<h1 id=\"samyy-bolshoy-chellenzh-v-zhizni\">Die gr\u00f6\u00dfte Herausforderung im Leben<\/h1>\n<p><\/p>\n<p><strong>Wladimir<\/strong>: Was ist mit den nicht-technischen Herausforderungen?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Die gr\u00f6\u00dfte Herausforderung war es, nicht\u2026 freundlich und nett zu den Menschen zu sein. Folglich fand ich mich st\u00e4ndig in hochgradig konfliktbeladenen Situationen wieder. In solchen, in denen ich wusste, dass alles schiefgeht, aber nicht wusste, wie ich mit den Problemen vorankommen sollte und es nicht schaffte, sie zu bew\u00e4ltigen. Zahlreiche langanhaltende Probleme, die Jahrzehnte dauerten, entstanden genau so. Dass es in Java die Compiler C1 und C2 gibt, ist die direkte Folge davon. Dass es in Java \u00fcber ein ganzes Jahrzehnt hinweg keine mehrstufige Kompilierung gab \u2013 das ist ebenfalls eine direkte Folge. Offensichtlich brauchten wir ein solches System, aber es ist nicht klar, warum es das nicht gab. Ich hatte Probleme mit einem Ingenieur\u2026 oder einer Gruppe von Ingenieuren. Vor langer Zeit, als ich anfing, bei Sun zu arbeiten, war ich\u2026 Gut, nicht nur damals, ich habe im Allgemeinen immer meine eigene Meinung zu allem. Und ich hielt es f\u00fcr eine Wahrheit, dass ich einfach meine Sichtweise direkt \u00e4u\u00dfern kann. Zumal ich die meiste Zeit erschreckend recht hatte. Und wenn dir dieser Ansatz nicht gef\u00e4llt\u2026 besonders wenn du offensichtlich im Unrecht bist und Unsinn redest\u2026 Nun, nur wenige Menschen konnten eine solche Kommunikationsform langm\u00fctig ertragen. Obwohl einige es konnten, zum Beispiel ich. Ich habe mein ganzes Leben auf meritokratischen Prinzipien aufgebaut. Wenn du mir etwas Falsches zeigst, drehe ich mich um und sage: Du hast Unsinn gesagt. Dabei entschuldige ich mich nat\u00fcrlich und all das, erkenne Verdienste an, falls vorhanden, und handle entsprechend. Auf der anderen Seite habe ich erschreckend oft recht, erschreckend viel Zeit. Und das funktioniert in zwischenmenschlichen Beziehungen nicht wirklich gut. Ich strebe nicht danach, nett zu sein, sondern stelle die Dinge klar. \u201eDas wird nie funktionieren, weil eins, zwei und drei\u201c. Und sie antworten: \u201eOh!\u201c. Es gab auch andere Konsequenzen, die ich besser auslassen sollte: zum Beispiel die, die zu meiner Scheidung von meiner Frau f\u00fchrten und zu einem Jahrzehnt der Depression danach.<\/p>\n<p><\/p>\n<p>Der Challenge ist ein Kampf mit den Menschen und ihrer Wahrnehmung dessen, was du tun kannst oder nicht, was wichtig ist und was nicht. Es gab viele Challenges zum Thema Programmierstil. Ich schreibe immer noch viel Code, aber damals musste ich sogar langsamer werden, weil ich zu viele Aufgaben parallel erledigte und sie schlecht machte, anstatt mich auf eine einzige zu konzentrieren. Wenn ich zur\u00fcckblicke, habe ich die H\u00e4lfte des Codes f\u00fcr das Java JIT Team, das C2 Team, geschrieben. Der n\u00e4chste schnellste Programmierer schrieb halb so schnell, der darauf folgende noch einmal halb so schnell und das war ein exponentieller R\u00fcckgang. Die siebte Person in dieser Reihe war sehr, sehr langsam \u2013 das passiert immer! Ich habe viel Code angesehen. Ich habe beobachtet, wer was schreibt, ohne Ausnahmen, ich habe mir ihren Code angeschaut, jede\/r von ihnen wurde \u00fcberpr\u00fcft und trotzdem habe ich immer noch mehr geschrieben als jeder von ihnen. Mit Menschen funktioniert dieser Ansatz nicht gut. Einige m\u00f6gen sowas nicht. Und wenn sie nicht damit umgehen k\u00f6nnen, fangen allerlei Beschwerden an. Zum Beispiel sagte man mir einmal, ich solle aufh\u00f6ren, Code zu schreiben, weil ich zu viel Code schreibe und das das Team gef\u00e4hrdet, und das klang f\u00fcr mich wie ein Scherz: Alter, wenn das gesamte Team verschwindet und ich weiterhin Code schreibe, verlierst du nur die H\u00e4lfte des Teams. Auf der anderen Seite, wenn ich weiterhin Code schreibe und du verlierst die H\u00e4lfte des Teams \u2013 das klingt nach sehr schlechtem Management. Ich habe nie besonders dar\u00fcber nachgedacht, nie dar\u00fcber gesprochen, aber es war trotzdem irgendwo in meinem Kopf. In den Hintergedanken schwirrte der Gedanke: \u201eMacht ihr ernsthaft Scherze?\u201c Also war ich das gr\u00f6\u00dfte Problem und meine Beziehung zu den Menschen. Jetzt verstehe ich mich viel besser, ich habe lange als Teamleiter bei Programmierern gearbeitet, und jetzt sage ich den Leuten direkt: Wei\u00dft du, ich bin, wie ich bin, und ihr m\u00fcsst damit umgehen \u2013 ist es in Ordnung, wenn ich hier stehe? Und als sie damit umzugehen begannen, hat alles funktioniert. Denn ich bin eigentlich weder schlecht noch gut, ich habe keine schlechten Absichten oder egoistischen Bestrebungen, das ist einfach mein Wesen, und damit muss man irgendwie leben.<\/p>\n<p><\/p>\n<p><strong>Andrey<\/strong>: Vor kurzem haben alle \u00fcber das Selbstbewusstsein f\u00fcr Introvertierte und generell \u00fcber soziale F\u00e4higkeiten gesprochen. Was kann man dazu sagen?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Ja, das war das Verst\u00e4ndnis und die Lektion, die ich aus der Scheidung von meiner Frau gezogen habe. Was ich aus der Scheidung gelernt habe, ist, mich selbst zu verstehen. So begann ich, andere Menschen zu verstehen. Zu verstehen, wie diese Interaktion funktioniert. Das f\u00fchrte zu einer Entdeckung nach der anderen. Es entstand das Bewusstsein, wer ich bin und was ich darstelle. Was ich tue: Entweder bin ich mit einer Aufgabe besch\u00e4ftigt, oder ich vermeide Konflikte, oder ich mache etwas anderes \u2013 und dieses Niveau des Selbstbewusstseins hilft wirklich, sich im Griff zu halten. Danach l\u00e4uft alles viel einfacher. Eine Sache, die ich nicht nur bei mir, sondern auch bei anderen Programmierern festgestellt habe, ist die Unf\u00e4higkeit, Gedanken zu verbalisieren, wenn man in einem emotionalen Stresszustand ist. Zum Beispiel, du sitzt dort und programmierst, bist im Fluss, und pl\u00f6tzlich kommen sie zu dir gerannt und schreien hysterisch, dass etwas kaputt ist und jetzt drastische Ma\u00dfnahmen gegen dich ergriffen werden. Und du kannst kein Wort sagen, weil du in einem emotionalen Stresszustand bist. Das erlernte Wissen erm\u00f6glicht es, sich auf diesen Moment vorzubereiten, ihn zu \u00fcberstehen und zu einem R\u00fcckzugsplan \u00fcberzugehen, nach dem man bereits etwas tun kann. Also ja, wenn du anf\u00e4ngst zu realisieren, wie das alles funktioniert \u2013 das ist ein gro\u00dfes, lebensver\u00e4nderndes Ereignis.\u00a0<br \/>\nIch selbst konnte die richtigen Worte nicht finden, aber ich erinnerte mich an die Abfolge der Handlungen. Die Essenz ist, dass diese Reaktion ebenso physisch wie verbal ist, und du brauchst Raum. Solchen Raum im zenbuddhistischen Sinn. Genau das muss erkl\u00e4rt werden, und dann musst du dich sofort physisch zur\u00fcckziehen. Wenn ich innerlich schweige, kann ich die Situation in Bezug auf Emotionen verarbeiten. W\u00e4hrend das Adrenalin das Gehirn erreicht, dich in den \u201eKampf oder Flucht\u201c-Modus schaltet, kannst du nichts mehr sagen, nein \u2013 jetzt bist du ein Idiot, ein Pr\u00fcgel, unf\u00e4hig, w\u00fcrdig zu antworten oder wenigstens den Angriff zu stoppen, und der Angreifer kann frei immer wieder angreifen. Zuerst musst du wieder du selbst werden, die Kontrolle zur\u00fcckgewinnen und aus dem \u201eKampf oder Flucht\u201c-Modus herauskommen. <\/p>\n<p><\/p>\n<p>Und daf\u00fcr ben\u00f6tigt man ein verbales Raum. Einfach freien Raum. Wenn man \u00fcberhaupt etwas sagen m\u00f6chte, kann man genau das festhalten und dann wirklich \u201eRaum\u201c f\u00fcr sich finden: im Park spazieren gehen, sich in die Dusche sperren - egal. Das Wichtigste ist, sich vor\u00fcbergehend von der Situation zu trennen. Sobald du sogar f\u00fcr ein paar Sekunden abschaltest, kommt die Kontrolle zur\u00fcck und du beginnst klar zu denken. \"Gut, ich bin doch kein Idiot oder so, ich mache keine dummen Dinge, ich bin ein ziemlich n\u00fctzlicher Mensch.\" Sobald du dich selbst \u00fcberzeugen konntest, ist es an der Zeit, zum n\u00e4chsten Schritt \u00fcberzugehen: zu verstehen, was geschehen ist. Du wurdest angegriffen, der Angriff kam von unerwarteter Seite, es war eine unfaire, hinterh\u00e4ltige Falle. Das ist schlecht. Der n\u00e4chste Schritt ist zu verstehen, warum der Angreifer das n\u00f6tig hatte. Warum eigentlich? Vielleicht weil er selbst w\u00fctend ist? Warum ist er w\u00fctend? Zum Beispiel, weil er selbst versagt hat und die Verantwortung nicht \u00fcbernehmen kann? So sollte man die gesamte Situation behutsam verarbeiten. Aber daf\u00fcr braucht man Spielraum, verbalen Raum. Der erste Schritt besteht darin, den verbalen Kontakt zu kappen. Weg von verbalen Diskussionen. Es abzubrechen, so schnell wie m\u00f6glich wegzugehen. Wenn es ein Telefonat ist \u2013 lege einfach auf \u2013 das ist eine F\u00e4higkeit, die ich aus der Kommunikation mit meiner Ex-Frau gelernt habe. Wenn das Gespr\u00e4ch zu nichts Gutem f\u00fchrt, sag einfach \u201eAuf Wiedersehen\u201c und lege auf. Auf der anderen Seite des Telefons: \u201ebla-bla-bla\u201c, du antwortest: \u201ehm, tsch\u00fcss!\u201c und legst auf. Du brichst einfach das Gespr\u00e4ch ab. F\u00fcnf Minuten sp\u00e4ter, wenn deine F\u00e4higkeit, klar zu denken, zur\u00fcckkommt, bist du etwas abgek\u00fchlt und es wird m\u00f6glich, zu \u00fcberlegen, was \u00fcberhaupt passiert ist und was als N\u00e4chstes kommt. Und beginne, eine durchdachte Antwort zu formulieren, anstatt einfach emotional zu reagieren. F\u00fcr mich war der Durchbruch im Selbstbewusstsein genau das, dass ich im Falle emotionalen Stresses nicht sprechen kann. Aus diesem Zustand herauszukommen, zu \u00fcberlegen und zu planen, wie man antworten und Probleme ausgleichen kann \u2013 das sind die richtigen Schritte, wenn man nicht sprechen kann. Der einfachste Weg ist, aus der Situation zu entkommen, in der emotionaler Stress auftritt, und einfach nicht mehr daran teilzunehmen. Danach gewinnst du die F\u00e4higkeit zu denken, wenn du denken kannst, entsteht die M\u00f6glichkeit zu sprechen und so weiter.<\/p>\n<p><\/p>\n<p>\u00dcbrigens versucht der Anwalt der Gegenseite im Gericht, dies mit dir zu tun \u2013 jetzt ist klar, warum. Weil er die M\u00f6glichkeit hat, dich in einen Zustand zu versetzen, in dem du sogar deinen eigenen Namen nicht aussprechen kannst, zum Beispiel. Im wahrsten Sinne des Wortes, du kannst nicht sprechen. Wenn dir das widerf\u00e4hrt und wenn du wei\u00dft, dass du an einem Ort sein wirst, wo es verbale K\u00e4mpfe gibt, an einem Ort wie dem Gericht, dann kannst du mit deinem Anwalt kommen. Der Anwalt wird dich verteidigen und den verbalen Angriff stoppen, und das auf ganz legale Weise, und du wirst deinen verlorenen Zen-Raum zur\u00fcckbekommen. Zum Beispiel musste ich ein paar Mal meine Familie anrufen, der Richter war damit ganz freundlich, aber der Anwalt der Gegenseite schrie und schrie mich an, ich konnte kein Wort einf\u00fcgen. In solchen F\u00e4llen funktioniert f\u00fcr mich am besten der Einsatz eines Vermittlers. Der Vermittler beendet all den Druck, der ununterbrochen auf dich einstr\u00f6mt, du entdeckst den notwendigen Zen-Raum, mit ihm kehrt die F\u00e4higkeit zum Sprechen zur\u00fcck. Es ist ein ganzes Wissensgebiet, in dem man viel lernen und vieles in sich selbst entdecken muss, und all dies verwandelt sich in hochgradige strategische Entscheidungen, die f\u00fcr verschiedene Menschen unterschiedlich sind. Einige haben nicht die oben beschriebenen Probleme, normalerweise haben Menschen, die beruflich im Verkauf t\u00e4tig sind, keine. All diese Menschen, die mit Worten ihren Lebensunterhalt verdienen \u2013 bekannte S\u00e4nger, Dichter, religi\u00f6se F\u00fchrer und Politiker, sie haben immer etwas zu sagen. Sie haben solche Probleme nicht, ich jedoch schon.<\/p>\n<p><\/p>\n<p><strong>Andrey<\/strong>: Das war\u2026 unerwartet. Gut, wir haben schon ziemlich viel gesprochen und es ist Zeit, dieses Interview zu beenden. Wir werden uns auf der Konferenz treffen und diesen Dialog fortsetzen k\u00f6nnen. Wir sehen uns auf der Hydra!<\/p>\n<p><\/p>\n<blockquote><p>Die Kommunikation mit Cliff kann auf der Konferenz Hydra 2019 fortgesetzt werden, die am 11. und 12. Juli 2019 in St. Petersburg stattfindet. Er wird mit einem Vortrag kommen <noindex><a rel=\"nofollow\" href=\"https:\/\/hydraconf.com\/2019\/talks\/2jix5mst7iduyp9linqhfj\/?utm_source=habr&amp;utm_medium=45871\">\u201eThe Azul Hardware Transactional Memory experience\u201c<\/a><\/noindex>. Tickets k\u00f6nnen erworben werden <noindex><a rel=\"nofollow\" href=\"https:\/\/hydraconf.ru\/?utm_source=habr&amp;utm_medium=458718\">auf der offiziellen Webseite<\/a><\/noindex>.<\/p><\/blockquote>\n<p>Quelle: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/jugru\/blog\/458718\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041a\u043b\u0438\u0444\u0444 \u041a\u043b\u0438\u043a \u2014 CTO \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438 Cratus (IoT \u0441\u0435\u043d\u0441\u043e\u0440\u044b \u0434\u043b\u044f \u0443\u043b\u0443\u0447\u0448\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0432), \u043e\u0441\u043d\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0438 \u0441\u043e\u043e\u0441\u043d\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0441\u0442\u0430\u0440\u0442\u0430\u043f\u043e\u0432 (\u0432\u043a\u043b\u044e\u0447\u0430\u044f Rocket Realtime School, Neurensic \u0438 H2O.ai) \u0441 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c\u0438 \u0443\u0441\u043f\u0435\u0448\u043d\u044b\u043c\u0438 \u044d\u043a\u0437\u0438\u0442\u0430\u043c\u0438. \u041a\u043b\u0438\u0444\u0444 \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u0441\u0432\u043e\u0439 \u043f\u0435\u0440\u0432\u044b\u0439 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440 \u0432 15 \u043b\u0435\u0442 (Pascal \u0434\u043b\u044f TRS Z-80)! \u041d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u0438\u0437\u0432\u0435\u0441\u0442\u0435\u043d \u0437\u0430 \u0440\u0430\u0431\u043e\u0442\u0443 \u043d\u0430\u0434 \u04212 \u0432 Java (the Sea of Nodes IR). \u042d\u0442\u043e\u0442 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440 \u043f\u043e\u043a\u0430\u0437\u0430\u043b [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-35851","post","type-post","status-publish","format-standard","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.1.1 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u041a\u043b\u0438\u0444\u0444 \u041a\u043b\u0438\u043a \u2014.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/bolshoe-intervyu-s-kliffom-klikom-ottsom-jit-kompilyatsii-v-java\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"de_DE\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u0411\u043e\u043b\u044c\u0448\u043e\u0435 \u0438\u043d\u0442\u0435\u0440\u0432\u044c\u044e \u0441 \u041a\u043b\u0438\u0444\u0444\u043e\u043c \u041a\u043b\u0438\u043a\u043e\u043c \u2014 \u043e\u0442\u0446\u043e\u043c JIT-\u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u0438 \u0432 Java | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041a\u043b\u0438\u0444\u0444 \u041a\u043b\u0438\u043a \u2014.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/bolshoe-intervyu-s-kliffom-klikom-ottsom-jit-kompilyatsii-v-java\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-31T19:07:03+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T19:07:03+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Gro\u00dfes Interview mit Cliff Click \u2013 dem Vater der JIT-Kompilierung in Java | ProHoster","description":"Cliff Click \u2014.","canonical_url":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/bolshoe-intervyu-s-kliffom-klikom-ottsom-jit-kompilyatsii-v-java","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"de_DE","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u0411\u043e\u043b\u044c\u0448\u043e\u0435 \u0438\u043d\u0442\u0435\u0440\u0432\u044c\u044e \u0441 \u041a\u043b\u0438\u0444\u0444\u043e\u043c \u041a\u043b\u0438\u043a\u043e\u043c \u2014 \u043e\u0442\u0446\u043e\u043c JIT-\u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u0438 \u0432 Java | ProHoster","og:description":"\u041a\u043b\u0438\u0444\u0444 \u041a\u043b\u0438\u043a \u2014.","og:url":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/bolshoe-intervyu-s-kliffom-klikom-ottsom-jit-kompilyatsii-v-java","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-10-31T19:07:03+00:00","article:modified_time":"2019-10-31T19:07:03+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"35851","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-22 01:01:19","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 01:55:25","updated":"2026-01-22 01:01:19","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts\/35851","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/comments?post=35851"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts\/35851\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/media?parent=35851"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/categories?post=35851"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/tags?post=35851"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}