Odličen intervju s Cliffom Clickom, očetom kompilacije JIT v Javi

Odličen intervju s Cliffom Clickom, očetom kompilacije JIT v JaviCliff Kliknite — Tehnični direktor podjetja Cratus (IoT senzorji za izboljšanje procesov), ustanovitelj in soustanovitelj več startupov (vključno z Rocket Realtime School, Neurensic in H2O.ai) z več uspešnimi izhodi. Cliff je napisal svoj prvi prevajalnik pri 15 letih (Pascal za TRS Z-80)! Najbolj znan je po svojem delu na C2 v Javi (The Sea of ​​​​Nodes IR). Ta prevajalnik je svetu pokazal, da JIT lahko proizvede visokokakovostno kodo, kar je bil eden od dejavnikov pri nastanku Jave kot ene glavnih sodobnih programskih platform. Nato je Cliff pomagal podjetju Azul Systems zgraditi 864-jedrni glavni računalnik s čisto programsko opremo Java, ki je podpirala prekinitve GC na 500-gigabajtni kopici v 10 milisekundah. Na splošno je Cliffu uspelo delati na vseh vidikih JVM.

 
Ta habrapost je odličen intervju s Cliffom. Pogovarjali se bomo o naslednjih temah:

  • Prehod na nizkonivojske optimizacije
  • Kako narediti veliko preoblikovanje
  • Stroškovni model
  • Usposabljanje optimizacije na nizki ravni
  • Praktični primeri izboljšanja zmogljivosti
  • Zakaj ustvariti svoj programski jezik
  • Kariera inženirja zmogljivosti
  • Tehnični izzivi
  • Nekaj ​​o dodelitvi registrov in večjedrnih jedrih
  • Največji izziv v življenju

Intervju vodi:

  • Andrej Satarin iz spletne storitve Amazon. V svoji karieri je uspel delati v popolnoma različnih projektih: testiral je porazdeljeno bazo podatkov NewSQL v Yandexu, sistem za zaznavanje oblakov v Kaspersky Labu, igro za več igralcev v Mail.ru in storitev za izračun deviznih cen v Deutsche Bank. Zanima me testiranje obsežnih zalednih in porazdeljenih sistemov.
  • Vladimir Sitnikov iz Netcrackerja. Deset let dela na področju zmogljivosti in razširljivosti NetCracker OS, programske opreme, ki jo telekomunikacijski operaterji uporabljajo za avtomatizacijo procesov upravljanja omrežja in omrežne opreme. Zanimajo me težave z zmogljivostjo Java in Oracle Database. Avtor več kot ducata izboljšav zmogljivosti v uradnem gonilniku PostgreSQL JDBC.

Prehod na nizkonivojske optimizacije

Andrew: Ste veliko ime v svetu kompilacije JIT, Jave in izvedbenega dela na splošno, kajne? 

Cliff: Tako je!

Andrew: Začnimo z nekaj splošnimi vprašanji o izvajalskem delu. Kaj menite o izbiri med optimizacijami na visoki in nizki ravni, kot je delo na ravni procesorja?

Cliff: Da, tukaj je vse preprosto. Najhitrejša koda je tista, ki se nikoli ne zažene. Zato morate vedno začeti z visoke ravni, delati na algoritmih. Boljši zapis O bo premagal slabši zapis O, razen če se vmešajo nekatere dovolj velike konstante. Nizke stvari gredo zadnje. Običajno je to nizka raven, če ste dovolj dobro optimizirali preostanek svojega sklada in je ostalo še nekaj zanimivih stvari. Toda kako začeti z visoke ravni? Kako veste, da je bilo opravljenega dovolj dela na visoki ravni? No... nikakor. Pripravljenih receptov ni. Morate razumeti problem, se odločiti, kaj boste storili (da ne boste v prihodnje delali nepotrebnih korakov) in potem lahko odkrijete profilerja, ki lahko pove kaj koristnega. Na neki točki sami ugotovite, da ste se znebili nepotrebnih stvari in da je čas za nekaj nizkostopenjskih finih nastavitev. To je vsekakor posebna zvrst umetnosti. Veliko ljudi dela nepotrebne stvari, vendar se premikajo tako hitro, da nimajo časa skrbeti za produktivnost. Ampak to je tako, dokler se vprašanje ne pojavi odkrito. Običajno 99% časa nikogar ne zanima, kaj počnem, vse do trenutka, ko se na kritični poti pojavi pomembna stvar, ki nikogar ne zanima. In tu ti vsi začnejo nagajati, "zakaj ni delovalo popolno že od samega začetka." Na splošno je vedno treba kaj izboljšati v zmogljivosti. Toda 99 % časa nimate potencialnih strank! Samo poskušaš doseči, da bi nekaj delovalo, in v tem procesu ugotoviš, kaj je pomembno. Nikoli ne moreš vnaprej vedeti, da mora biti ta kos popoln, zato moraš biti pravzaprav popoln v vsem. Toda to je nemogoče in tega ne storite. Vedno je treba marsikaj popraviti – in to je povsem normalno.

Kako narediti veliko preoblikovanje

Andrew: Kako delaš na nastopu? To je medsektorski problem. Ali ste se na primer kdaj morali ukvarjati s težavami, ki izhajajo iz presečišča številnih obstoječih funkcij?

Cliff: Poskušam se temu izogniti. Če vem, da bo zmogljivost težava, razmislim o tem, preden začnem kodirati, zlasti s podatkovnimi strukturami. A pogosto vse to odkriješ zelo kasneje. In potem moraš poseči po skrajnih ukrepih in narediti to, čemur jaz pravim "prepisati in osvojiti": zgrabiti moraš dovolj velik del. Nekaj ​​kode bo vseeno treba prepisati zaradi težav z delovanjem ali česa drugega. Ne glede na razlog za prepisovanje kode je skoraj vedno bolje prepisati večji kot manjši del. V tem trenutku se vsi začnejo tresti od strahu: "o moj bog, ne smeš se dotakniti toliko kode!" Toda v resnici ta pristop skoraj vedno deluje veliko bolje. Takoj se morate lotiti velikega problema, okoli njega narisati velik krog in reči: vse bom prepisal znotraj kroga. Obroba je veliko manjša od vsebine v njej, ki jo je treba zamenjati. In če vam takšna začrtanost meja omogoča, da delo v notranjosti opravite odlično, imate proste roke, počnite, kar želite. Ko enkrat razumete težavo, je postopek ponovnega pisanja veliko lažji, zato močno ugriznite!
Istočasno, ko naredite veliko prepisovanje in ugotovite, da bo uspešnost težava, vas lahko to takoj začne skrbeti. To se običajno spremeni v preproste stvari, kot je "ne kopiraj podatkov, upravljaj podatke čim bolj preprosto, naj bodo majhni." Pri velikih prepisih obstajajo standardni načini za izboljšanje zmogljivosti. In skoraj vedno se vrtijo okoli podatkov.

Stroškovni model

Andrew: V enem od podcastov ste govorili o stroškovnih modelih v kontekstu produktivnosti. Lahko pojasnite, kaj ste mislili s tem?

Cliff: Vsekakor. Rodil sem se v dobi, ko je bila zmogljivost procesorja izjemno pomembna. In to obdobje se spet vrača - usoda ni brez ironije. Začel sem živeti v dneh osembitnih strojev; moj prvi računalnik je delal z 256 bajti. Točno bajti. Vse je bilo zelo majhno. Navodila je bilo treba prešteti in ko smo se začeli pomikati navzgor po nizu programskih jezikov, so jeziki postajali čedalje večji. Bil je Assembler, nato Basic, nato C, C pa je poskrbel za veliko podrobnosti, kot je dodeljevanje registrov in izbira ukazov. Toda tam je bilo vse povsem jasno in če bi naredil kazalec na primerek spremenljivke, bi dobil obremenitev in cena tega navodila je znana. Strojna oprema proizvede določeno število strojnih ciklov, zato je mogoče hitrost izvajanja različnih stvari izračunati preprosto tako, da seštejete vsa navodila, ki jih boste zagnali. Vsako primerjavo/testiranje/vejo/klic/nalaganje/shranjevanje bi lahko sešteli in rekli: to je čas izvedbe za vas. Ko delate na izboljšanju zmogljivosti, boste zagotovo pozorni na to, katere številke ustrezajo majhnim vročim ciklom. 
A takoj, ko preklopiš na Javo, Python in podobne stvari, se zelo hitro oddaljiš od nizkonivojske strojne opreme. Kakšni so stroški klica getterja v Javi? Če je JIT v HotSpot pravilen vstavljeno, se bo naložil, če pa tega ni storil, bo klic funkcije. Ker je klic v vroči zanki, bo preglasil vse druge optimizacije v tej zanki. Zato bodo realni stroški veliko višji. In takoj izgubite možnost, da pogledate del kode in razumete, da bi jo morali izvesti glede na hitrost procesorja, uporabljeni pomnilnik in predpomnilnik. Vse to postane zanimivo šele, če se zares vživiš v predstavo.
Zdaj smo se znašli v situaciji, ko se hitrosti procesorjev skorajda niso povečale že desetletje. Stari časi so nazaj! Ne morete več računati na dobro enonitno delovanje. Če pa nenadoma prideš v vzporedno računalništvo, je to neverjetno težko, vsi gledajo nate kot na Jamesa Bonda. Desetkratni pospeški se tukaj običajno pojavijo na mestih, kjer je nekdo kaj zamočil. Sočasnost zahteva veliko dela. Če želite doseči to XNUMX-kratno pospešitev, morate razumeti model stroškov. Kaj in koliko stane? Če želite to narediti, morate razumeti, kako se jezik prilega osnovni strojni opremi.
Martin Thompson je za svoj blog izbral odlično besedo Mehanska simpatija! Razumeti morate, kaj bo strojna oprema naredila, kako točno bo to storila in zakaj sploh počne to, kar počne. Z uporabo tega je dokaj enostavno začeti šteti navodila in ugotoviti, kam gre čas izvajanja. Če nimaš ustrezne izobrazbe, pač iščeš črno mačko v temni sobi. Vidim ljudi, ki ves čas optimizirajo delovanje in nimajo pojma, kaj za vraga počnejo. Zelo trpijo in ne napredujejo veliko. In ko vzamem isti kos kode, vstavim nekaj majhnih vdorov in dobim pet- ali desetkratno pospešitev, mi rečejo: no, to ni pošteno, vedeli smo že, da si boljši. Neverjetno. O čem govorim ... model stroškov je o tem, kakšno kodo napišete in kako hitro v povprečju teče v veliki sliki.

Andrew: In kako lahko obdržiš tako količino v glavi? Se to doseže z več izkušnjami ali? Od kod takšne izkušnje?

Cliff: No, svoje izkušnje nisem dobil na najlažji način. Programiral sem v Assembly v dneh, ko si lahko razumel vsako posamezno navodilo. Sliši se neumno, a od takrat je nabor navodil Z80 vedno ostal v moji glavi, v spominu. Ne spomnim se imen ljudi v minuti pogovora, spomnim pa se kode, napisane pred 40 leti. Smešno je, izgleda kot sindrom "idiot znanstvenik".

Usposabljanje optimizacije na nizki ravni

Andrew: Ali obstaja lažji način vstopa?

Cliff: Da in ne. Strojna oprema, ki jo vsi uporabljamo, se skozi čas ni toliko spremenila. Vsi uporabljajo x86, z izjemo pametnih telefonov Arm. Če ne delate nekakšne hardcore vdelave, delate isto stvar. V redu, naslednji. Tudi navodila se že stoletja niso spremenila. Moraš iti in nekaj napisati v skupščino. Ne veliko, a dovolj, da začnem razumeti. Ti se smejiš, ampak jaz govorim popolnoma resno. Razumeti morate ujemanje med jezikom in strojno opremo. Potem morate iti malo pisati in narediti majhen prevajalnik igrač za mali jezik igrač. Podobno igrači pomeni, da mora biti izdelano v razumnem času. Lahko je zelo preprosto, vendar mora ustvariti navodila. Dejanje generiranja navodil vam bo pomagalo razumeti stroškovni model za most med visokonivojsko kodo, ki jo pišejo vsi, in strojno kodo, ki se izvaja na strojni opremi. Ta korespondenca se bo vžgala v možgane v času pisanja prevajalnika. Tudi najpreprostejši prevajalnik. Po tem lahko začnete gledati na Javo in dejstvo, da je njen pomenski prepad veliko globlji in je veliko težje graditi mostove čez njega. V Javi je veliko težje razumeti, ali se je naš most izkazal za dobrega ali slabega, kaj bo povzročilo, da bo razpadel in kaj ne. Toda potrebujete nekakšno izhodišče, kjer pogledate kodo in razumete: "ja, ta getter bi moral biti vstavljen vsakič." In potem se izkaže, da se to včasih zgodi, razen v primeru, ko metoda postane prevelika in JIT začne vstavljati vse. Učinkovitost takšnih krajev je mogoče predvideti takoj. Običajno pridobivalniki delujejo dobro, potem pa pogledate velike vroče zanke in ugotovite, da tam okoli plavajo nekateri klici funkcij, ki ne vedo, kaj počnejo. To je težava pri široki uporabi geterjev. Razlog, zakaj niso vstavljeni, je, da ni jasno, ali so getterji. Če imate super majhno bazo kode, si jo lahko preprosto zapomnite in nato rečete: to je getter, to pa je setter. V veliki kodni bazi vsaka funkcija živi svojo zgodovino, ki je na splošno nikomur ne poznamo. Profiler pravi, da smo pri neki zanki izgubili 24 % časa in da bi razumeli, kaj ta zanka počne, moramo pogledati vsako funkcijo znotraj. Tega je nemogoče razumeti brez študija funkcije, kar resno upočasni proces razumevanja. Zato ne uporabljam geterjev in setterjev, dosegel sem novo raven!
Kje dobiti model stroškov? No, kaj lahko preberete, seveda ... Ampak mislim, da je najboljši način, da ukrepate. Izdelava majhnega prevajalnika bo najboljši način, da razumete stroškovni model in ga prilagodite svoji glavi. Majhen prevajalnik, ki bi bil primeren za programiranje mikrovalovne pečice, je naloga za začetnika. No, mislim, če že imate znanje programiranja, potem bi moralo biti to dovolj. Vse te stvari, kot je razčlenjevanje niza, ki ga imate kot nekakšen algebraični izraz, ekstrahiranje navodil za matematične operacije od tam v pravilnem vrstnem redu, jemanje pravilnih vrednosti iz registrov - vse to se naredi naenkrat. In medtem ko to počnete, se vam bo vtisnilo v možgane. Mislim, da vsi vedo, kaj počne prevajalnik. To bo omogočilo razumevanje stroškovnega modela.

Praktični primeri izboljšanja zmogljivosti

Andrew: Na kaj morate biti še pozorni, ko delate na produktivnosti?

Cliff: Podatkovne strukture. Mimogrede, ja, že dolgo nisem učil teh predavanj ... Raketna šola. Bilo je zabavno, a zahtevalo je veliko truda, pa še življenje imam! V REDU. Tako sem v enem od velikih in zanimivih predavanj, »Kam gre vaša uspešnost,« študentom dal primer: dva in pol gigabajta fintech podatkov je bilo prebranih iz datoteke CSV, nato pa so morali izračunati število prodanih izdelkov. . Redni podatki o trgu. Paketi UDP pretvorjeni v besedilno obliko od 70. let prejšnjega stoletja. Chicago Mercantile Exchange - vse vrste stvari, kot so maslo, koruza, soja, podobne stvari. Treba je bilo prešteti te produkte, število transakcij, povprečni obseg pretoka sredstev in blaga itd. To je precej preprosta trgovalna matematika: poiščite kodo izdelka (to je 1-2 znaka v zgoščevalni tabeli), pridobite znesek, ga dodajte enemu od sklopov trgovanja, dodajte količino, dodajte vrednost in še nekaj drugih stvari. Zelo preprosta matematika. Implementacija igrače je bila zelo enostavna: vse je v datoteki, datoteko berem in se premikam po njej, posamezne zapise razdelim na javanske nize, v njih iščem potrebne stvari in jih seštevam glede na zgoraj opisano matematiko. In deluje pri neki nizki hitrosti.

S tem pristopom je očitno, kaj se dogaja, vzporedno računalništvo pa ne bo pomagalo, kajne? Izkazalo se je, da je mogoče petkratno povečanje zmogljivosti doseči preprosto z izbiro pravih podatkovnih struktur. In to preseneti celo izkušene programerje! V mojem konkretnem primeru je bil trik v tem, da ne smete dodeljevati pomnilnika v vroči zanki. No, to ni cela resnica, ampak na splošno - ne bi smeli poudarjati "enkrat v X", ko je X dovolj velik. Ko je X dva gigabajta in pol, ne bi smeli dodeliti ničesar "enkrat na črko", "enkrat na vrstico" ali "enkrat na polje", kaj podobnega. Tukaj se porabi čas. Kako to sploh deluje? Predstavljajte si, da kličem String.split() ali BufferedReader.readLine(). Readline naredi niz iz nabora bajtov, ki so prišli po omrežju, enkrat za vsako vrstico, za vsako od stotin milijonov vrstic. Vzamem to vrstico, jo razčlenim in zavržem. Zakaj ga vržem stran - no, to sem že obdelal, to je vse. Torej, za vsak bajt, prebran iz teh 2.7G, bosta v vrstici zapisana dva znaka, torej že 5.4G, in jih ne potrebujem za nič naprej, zato jih vržemo stran. Če pogledate pasovno širino pomnilnika, naložimo 2.7 G, ki gre skozi pomnilnik in pomnilniško vodilo v procesorju, nato pa se dvakrat toliko pošlje v linijo, ki leži v pomnilniku, in vse to se raztrga, ko se ustvari vsaka nova linija. Ampak to moram prebrati, strojna oprema to prebere, tudi če je kasneje vse obrabljeno. In to moram zapisati, ker sem ustvaril vrstico in so predpomnilniki polni - predpomnilnik ne more sprejeti 2.7 G. Torej za vsak bajt, ki ga preberem, preberem še dva bajta in zapišem še dva bajta, na koncu pa imajo razmerje 4:1 - v tem razmerju zapravljamo pasovno širino pomnilnika. In potem se izkaže, da če se String.split() – to ni zadnjič, da to počnem, morda je notri še 6-7 polj. Torej klasična koda branja CSV in nato razčlenjevanja nizov povzroči izgubo pasovne širine pomnilnika približno 14:1 glede na tisto, kar bi dejansko želeli imeti. Če zavržete te izbire, lahko dobite petkratno pospešitev.

In ni tako težko. Če kodo pogledate iz pravega zornega kota, postane vse precej preprosto, ko se zavete težave. Ne bi smeli povsem prenehati z dodeljevanjem pomnilnika: edina težava je v tem, da nekaj dodelite in takoj zamre, ob tem pa požge pomemben vir, ki je v tem primeru pasovna širina pomnilnika. In vse to ima za posledico padec produktivnosti. Na x86 morate običajno aktivno zapisovati procesorske cikle, tukaj pa ste porabili ves pomnilnik veliko prej. Rešitev je zmanjšanje količine izcedka. 
Drugi del težave je, da če zaženete profiler, ko zmanjka pomnilniškega traku, takoj ko se to zgodi, običajno čakate, da se predpomnilnik vrne, ker je poln smeti, ki ste jo pravkar ustvarili, vseh teh vrstic. Zato postane vsaka operacija nalaganja ali shranjevanja počasna, ker povzročijo napake v predpomnilniku – celoten predpomnilnik je postal počasen in čaka, da ga smeti zapustijo. Zato bo profiler prikazal samo topel naključni šum, razmazan po celotni zanki - v kodi ne bo ločenega vročega navodila ali mesta. Samo hrup. In če pogledate cikle GC, so vsi mlade generacije in super hitri - največ mikrosekund ali milisekund. Navsezadnje ves ta spomin takoj umre. Vi dodelite milijarde gigabajtov, on pa jih reže, reže in še enkrat reže. Vse to se zgodi zelo hitro. Izkazalo se je, da obstajajo poceni cikli GC, topel šum vzdolž celotnega cikla, vendar želimo doseči 5-kratno pospešitev. V tem trenutku bi se moralo v vaši glavi nekaj zapreti in zazveneti: "zakaj je to?!" Presežek pomnilniškega traku ni prikazan v klasičnem razhroščevalniku; zagnati morate razhroščevalnik števca zmogljivosti strojne opreme in si ga ogledati sami in neposredno. Toda tega ni mogoče neposredno sumiti iz teh treh simptomov. Tretji simptom je, ko pogledate, kaj poudarjate, vprašate profilerja in ta odgovori: "Naredili ste milijardo vrstic, vendar je GC delal brezplačno." Takoj ko se to zgodi, ugotovite, da ste ustvarili preveč predmetov in požgali celotno spominsko stezo. Obstaja način, da to ugotovimo, vendar ni očiten. 

Težava je v podatkovni strukturi: gola struktura, ki je podlaga za vse, kar se zgodi, je prevelika, ima 2.7 G na disku, zato je izdelava kopije te stvari zelo nezaželena - želite jo takoj naložiti iz omrežnega medpomnilnika bajtov v registre, da ne bi petkrat brali-pisali v vrstico naprej in nazaj. Na žalost vam Java privzeto ne ponuja takšne knjižnice kot dela JDK. Ampak to je trivialno, kajne? V bistvu je to 5-10 vrstic kode, ki bodo uporabljene za implementacijo vašega lastnega nalagalnika nizov v medpomnilniku, ki ponavlja vedenje razreda nizov, hkrati pa je ovoj okoli osnovnega medpomnilnika bajtov. Posledično se izkaže, da delate skoraj kot z nizi, v resnici pa se kazalci na vmesni pomnilnik premikajo tja in neobdelani bajti niso nikamor kopirani, zato se isti medpomnilniki znova in znova uporabljajo in operacijski sistem z veseljem prevzame stvari, za katere je zasnovan, na primer skrito dvojno medpomnjenje teh bajtnih medpomnilnikov, in ne brskate več po neskončnem toku nepotrebnih podatkov. Mimogrede, ali razumete, da je pri delu z GC zagotovljeno, da vsaka dodelitev pomnilnika ne bo vidna procesorju po zadnjem ciklu GC? Zato vse to nikakor ne more biti v predpomnilniku in potem pride do 100% zagotovljenega zgrešenega. Pri delu s kazalcem na x86 odštevanje registra iz pomnilnika traja 1-2 takta in takoj ko se to zgodi, plačaš, plačaš, plačaš, ker je pomnilnik ves vklopljen DEVET predpomnilnikov – in to je strošek dodeljevanja pomnilnika. Prava vrednost.

Z drugimi besedami, podatkovne strukture je najtežje spremeniti. In ko ugotovite, da ste izbrali napačno strukturo podatkov, ki bo kasneje uničila zmogljivost, je običajno treba opraviti veliko dela, a če tega ne storite, se bodo stvari poslabšale. Najprej morate razmišljati o podatkovnih strukturah, to je pomembno. Glavni strošek pri tem pade na debele podatkovne strukture, ki se začnejo uporabljati v slogu "podatkovno strukturo X sem kopiral v podatkovno strukturo Y, ker mi je bolj všeč oblika Y." Toda operacija kopiranja (ki se zdi poceni) dejansko zapravlja pasovno širino pomnilnika in tam je zakopan ves izgubljeni čas izvajanja. Če imam ogromen niz JSON in ga želim spremeniti v strukturirano drevo DOM POJO-jev ali kaj podobnega, bo operacija razčlenjevanja tega niza in gradnje POJO-ja ter nato ponoven dostop do POJO-ja pozneje povzročila nepotrebne stroške – to je ni poceni. Razen če tečete okoli POJO veliko pogosteje kot okoli vrvice. Namesto tega lahko poskusite dešifrirati niz in od tam izvleči samo tisto, kar potrebujete, ne da bi ga spremenili v kakršen koli POJO. Če se vse to zgodi na poti, od katere se zahteva največja zmogljivost, ni POJO za vas, morate nekako neposredno zariti v linijo.

Zakaj ustvariti svoj programski jezik

Andrew: Rekli ste, da morate za razumevanje stroškovnega modela napisati svoj jezik ...

Cliff: Ni jezik, ampak prevajalnik. Jezik in prevajalnik sta dve različni stvari. Najpomembnejša razlika je v glavi. 

Andrew: Mimogrede, kolikor vem, eksperimentirate z ustvarjanjem lastnih jezikov. Za kaj?

Cliff: Ker lahko! Sem napol upokojen, zato je to moj hobi. Vse svoje življenje uporabljam jezike drugih ljudi. Veliko sem delal tudi na svojem slogu kodiranja. In tudi zato, ker vidim težave v drugih jezikih. Vidim, da obstajajo boljši načini za početje znanih stvari. In bi jih uporabil. Naveličan sem videnja težav pri sebi, v Javi, Pythonu ali katerem koli drugem jeziku. Zdaj pišem v React Native, JavaScript in Elm kot hobi, ki ni povezan z upokojitvijo, ampak z aktivnim delom. Pišem tudi v Pythonu in najverjetneje bom še naprej delal na strojnem učenju za ozadja Java. Obstaja veliko priljubljenih jezikov in vsi imajo zanimive funkcije. Vsak je dober na svoj način in lahko poskusite združiti vse te lastnosti. Torej preučujem stvari, ki me zanimajo, obnašanje jezika, poskušam priti do razumne semantike. In zaenkrat mi uspeva! Trenutno se mučim s pomnilniško semantiko, ker želim imeti tako kot v C in Javi ter dobiti močan pomnilniški model in pomnilniško semantiko za nalaganja in shranjevanja. Hkrati imejte samodejno sklepanje o vrsti kot v Haskell-u. Tu poskušam združiti sklepanje o vrsti, podobno Haskellu, z delom pomnilnika v C in Javi. To sem počel zadnje 2-3 mesece npr.

Andrew: Če zgradite jezik, ki vzame boljše vidike drugih jezikov, ali mislite, da bo nekdo naredil nasprotno: vzel vaše ideje in jih uporabil?

Cliff: Točno tako se pojavijo novi jeziki! Zakaj je Java podobna C-ju? Ker je imel C dobro sintakso, ki so jo razumeli vsi, in Java se je zgledovala po tej sintaksi, dodala je varnost tipov, preverjanje meja polja, GC, izboljšali pa so tudi nekatere stvari iz C. Dodali so svoje. Vendar so bili navdihnjeni precej, kajne? Vsi stojijo na ramenih velikanov, ki so prišli pred vami – tako se napreduje.

Andrew: Kolikor razumem, bo vaš jezik varen za spomin. Ali ste razmišljali o implementaciji nečesa, kot je preverjanje izposoje iz Rusta? Ste ga pogledali, kaj mislite o njem?

Cliff: No, že dolgo pišem C, z vsem tem malloc in free ter ročno upravljam življenjsko dobo. Veste, 90-95 % ročno nadzorovane življenjske dobe ima enako strukturo. In zelo, zelo boleče je to početi ročno. Želel bi, da vam prevajalnik preprosto pove, kaj se tam dogaja in kaj ste s svojimi dejanji dosegli. Za nekatere stvari borrow checker to stori takoj po namestitvi. In mora samodejno prikazati informacije, razumeti vse in me niti ne obremenjevati s predstavitvijo tega razumevanja. Opraviti mora vsaj lokalno analizo pobegov in le, če ne uspe, mora dodati opombe tipa, ki bodo opisale življenjsko dobo - in taka shema je veliko bolj zapletena kot preverjalnik izposoje ali katerega koli obstoječega preverjalnika pomnilnika. Izbira med "vse je v redu" in "ničesar ne razumem" - ne, mora biti nekaj boljšega. 
Torej, kot nekdo, ki je napisal veliko kode v C, menim, da je podpora za samodejni nadzor življenjske dobe najpomembnejša stvar. Prav tako sem sita tega, koliko Java uporablja pomnilnik in glavna pritožba je GC. Ko dodelite pomnilnik v Javi, ne boste dobili nazaj pomnilnika, ki je bil lokalni v zadnjem ciklu GC. To ne velja za jezike z natančnejšim upravljanjem pomnilnika. Če pokličete malloc, takoj dobite pomnilnik, ki je bil običajno pravkar uporabljen. Običajno s spominom naredite nekaj začasnih stvari in jih takoj vrnete nazaj. Takoj se vrne v bazen malloc in naslednji cikel malloc ga spet potegne ven. Zato je dejanska uporaba pomnilnika zmanjšana na nabor živih objektov v danem času, plus puščanja. In če vse skupaj ne uhaja na povsem nespodoben način, večina pomnilnika konča v predpomnilnikih in procesorju, deluje pa hitro. Vendar zahteva veliko ročnega upravljanja pomnilnika z malloc in free, klicanimi v pravem vrstnem redu, na pravem mestu. Rust lahko sam to pravilno opravi in ​​v mnogih primerih zagotovi celo boljšo zmogljivost, saj je poraba pomnilnika zožena samo na trenutni izračun - v nasprotju s čakanjem na naslednji cikel GC, da sprosti pomnilnik. Kot rezultat smo dobili zelo zanimiv način za izboljšanje delovanja. In precej močan – mislim, delal sem takšne stvari pri obdelavi podatkov za fintech in to mi je omogočilo približno petkratno pospešitev. To je precejšnja spodbuda, zlasti v svetu, kjer procesorji ne postajajo hitrejši in še vedno čakamo na izboljšave.

Kariera inženirja zmogljivosti

Andrew: Prav tako bi rad povprašal o karieri na splošno. Postali ste pomembni s svojim JIT delom v HotSpotu in se nato preselili v Azul, ki je prav tako podjetje JVM. Vendar smo že prej delali več na strojni opremi kot na programski opremi. In potem so nenadoma prešli na velike podatke in strojno učenje ter nato na odkrivanje goljufij. Kako se je to zgodilo? Gre za zelo različna področja razvoja.

Cliff: S programiranjem se ukvarjam že kar dolgo in uspelo mi je obiskovati veliko različnih predavanj. In ko ljudje rečejo: "oh, ti si tisti, ki je naredil JIT za Javo!", je vedno smešno. Pred tem pa sem delal na klonu PostScripta - jezika, ki ga je Apple nekoč uporabljal za svoje laserske tiskalnike. In pred tem sem naredil implementacijo jezika Forth. Mislim, da je zame skupna tema razvoj orodij. Vse življenje izdelujem orodja, s katerimi drugi ljudje pišejo svoje kul programe. Sodeloval pa sem tudi pri razvoju operacijskih sistemov, gonilnikov, razhroščevalnikov na ravni jedra, jezikov za razvoj OS, ki so se začeli trivialno, sčasoma pa so postali vse bolj zapleteni. Toda glavna tema je še vedno razvoj orodij. Velik del mojega življenja je minil med Azulom in Sunom, šlo pa je za Javo. Toda ko sem začel z velikimi podatki in strojnim učenjem, sem si ponovno nadel modni klobuk in rekel: "Oh, zdaj imamo nepomembno težavo in veliko zanimivih stvari se dogaja in ljudje počnejo stvari." To je odlična razvojna pot.

Da, res obožujem porazdeljeno računalništvo. Moja prva zaposlitev je bila kot študent C, na oglaševalskem projektu. To je bilo porazdeljeno računalništvo na čipih Zilog Z80, ki je zbiralo podatke za analogni OCR, ki jih je ustvaril pravi analogni analizator. Bila je kul in popolnoma nora tema. Vendar so bile težave, kakšen del ni bil pravilno prepoznan, zato si moral vzeti sliko in jo pokazati osebi, ki je že znala brati z očmi in poročati, kaj piše, in zato so bila opravila s podatki in ta opravila imeli svoj jezik. Obstajalo je zaledje, ki je vse to obdelovalo - Z80 je deloval vzporedno z delujočimi terminali vt100 - eden na osebo, na Z80 pa je bil model vzporednega programiranja. Nekaj ​​skupnega pomnilnika, ki si ga delijo vsi Z80 v zvezdni konfiguraciji; Tudi hrbtna plošča je bila v skupni rabi, polovica RAM-a pa je bila v skupni rabi znotraj omrežja, druga polovica pa je bila zasebna ali pa je bila namenjena nečemu drugemu. Smiselno zapleten vzporedni porazdeljeni sistem s skupnim... delnim pomnilnikom. Kdaj je bilo to ... sploh se ne spomnim, nekje sredi 80. let. Precej dolgo nazaj. 
Da, predpostavimo, da je 30 let precej dolga doba nazaj. Težave, povezane s porazdeljenim računalništvom, obstajajo že precej dolgo; ljudje so že dolgo v vojni z Beowulf- grozdi. Takšne gruče izgledajo kot ... Na primer: obstaja Ethernet in vaš hitri x86 je povezan s tem Ethernetom, zdaj pa želite dobiti lažni skupni pomnilnik, ker takrat nihče ni mogel izvajati porazdeljenega računalniškega kodiranja, bilo je pretežko in zato obstaja je bil lažni skupni pomnilnik z zaščitnimi pomnilniškimi stranmi na x86, in če ste pisali na to stran, smo drugim procesorjem povedali, da če bodo dostopali do istega skupnega pomnilnika, ga bo treba naložiti od vas in s tem nekaj podobnega protokolu za podporo pojavila se je skladnost predpomnilnika in programska oprema za to. Zanimiv koncept. Resnična težava je bila seveda nekaj drugega. Vse to je delovalo, vendar ste hitro dobili težave z zmogljivostjo, ker nihče ni razumel modelov zmogljivosti na dovolj dobri ravni - kakšni vzorci dostopa do pomnilnika so bili tam, kako zagotoviti, da se vozlišča neskončno pingajo drug drugemu itd.

V H2O sem ugotovil, da so razvijalci sami odgovorni za določanje, kje je paralelizem skrit in kje ne. Prišel sem do modela kodiranja, ki je pisanje visoko zmogljive kode naredil enostavno in preprosto. Toda pisanje počasi delujoče kode je težko, videti bo slabo. Morate resno poskusiti napisati počasno kodo, morali boste uporabiti nestandardne metode. Zavorna koda je vidna na prvi pogled. Posledično običajno pišete kodo, ki deluje hitro, vendar morate ugotoviti, kaj storiti v primeru skupnega pomnilnika. Vse to je povezano z velikimi nizi in vedenje tam je podobno nehlapnim velikim nizom v vzporedni Javi. Mislim, predstavljajte si, da dve niti pišeta v vzporedno polje, ena od njiju zmaga, druga pa izgubi in ne veste, katera je katera. Če niso nestanovitni, je vrstni red lahko kakršenkoli želite - in to zelo dobro deluje. Ljudem je resnično mar za vrstni red operacij, volatile postavijo na prava mesta in pričakujejo težave z zmogljivostjo, povezane s pomnilnikom, na pravih mestih. V nasprotnem primeru bi preprosto napisali kodo v obliki zank od 1 do N, kjer je N nekaj trilijonov, v upanju, da bodo vsi kompleksni primeri samodejno postali vzporedni - in tam ne deluje. Toda v H2O to ni niti Java niti Scala; če želite, ga lahko smatrate za "Java minus minus". To je zelo jasen stil programiranja in je podoben pisanju preproste kode C ali Java z zankami in nizi. Toda hkrati je mogoče pomnilnik obdelati v terabajtih. Še vedno uporabljam H2O. Od časa do časa ga uporabljam v različnih projektih - in še vedno je najhitrejša stvar, več desetkrat hitrejša od svojih konkurentov. Če delate velike podatke s stolpčnimi podatki, je zelo težko premagati H2O.

Tehnični izzivi

Andrew: Kaj je bil vaš največji izziv v celotni karieri?

Cliff: Ali razpravljamo o tehničnem ali netehničnem delu vprašanja? Rekel bi, da največji izzivi niso tehnični. 
Kar se tiče tehničnih izzivov. Enostavno sem jih premagal. Sploh ne vem, kateri je bil največji, bilo pa je nekaj precej zanimivih, ki so vzeli kar nekaj časa, psihične borbe. Ko sem šel v Sun, sem bil prepričan, da bom naredil hiter prevajalnik, en kup starejših pa je odgovorilo, da mi nikoli ne bo uspelo. Toda šel sem po tej poti, zapisal prevajalnik do dodeljevalnika registrov in bilo je precej hitro. Bil je tako hiter kot sodobni C1, vendar je bil alokator takrat veliko počasnejši in za nazaj je bil to velik problem strukture podatkov. Potreboval sem ga za pisanje grafičnega delilnika registrov in nisem razumel dileme med izraznostjo kode in hitrostjo, ki je obstajala v tistem obdobju in je bila zelo pomembna. Izkazalo se je, da podatkovna struktura običajno presega velikost predpomnilnika na x86 tistega časa, in zato, če sem sprva domneval, da bo razdeljevalnik registrov obdelal 5-10 odstotkov celotnega časa tresenja, potem se je v resnici izkazalo, da 50 odstotkov.

Sčasoma je prevajalnik postal čistejši in učinkovitejši, v več primerih je prenehal generirati strašno kodo, zmogljivost pa je vse bolj spominjala na prevajalnik C. Razen seveda, če napišete kakšno bedarijo, da niti C ne pospeši . Če pišete kodo, kot je C, boste v več primerih dosegli zmogljivost, kot je C. In dlje kot si šel, pogosteje si dobil kodo, ki je asimptotično sovpadala z nivojem C, dodeljevalec registrov je začel izgledati kot nekaj popolnega ... ne glede na to, ali tvoja koda teče hitro ali počasi. Nadaljeval sem z delom na razdelilniku, da bi omogočal boljše izbire. Postajal je vse počasnejši, vendar je vedno bolje deloval v primerih, ko nihče drug ni bil kos. Lahko bi se poglobil v razdelilnik registra, tam zakopal mesec dela in nenadoma bi se celotna koda začela izvajati 5 % hitreje. To se je dogajalo vedno znova in razdelilnik je postal nekakšna umetnina - vsi so ga imeli radi ali sovražili, ljudje z akademije pa so postavljali vprašanja na temo "zakaj je vse tako narejeno", zakaj ne. črtno skeniranje, in kakšna je razlika. Odgovor je še vedno enak: alokator, ki temelji na barvanju grafov in zelo skrbnem delu s kodo vmesnega pomnilnika, je enako orožje zmage, najboljša kombinacija, ki je nihče ne more premagati. In to je precej neočitna stvar. Vse ostalo, kar prevajalec tam počne, so dokaj naštudirane stvari, čeprav tudi spravljene na raven umetnosti. Vedno sem delal stvari, ki naj bi prevajalnik spremenile v umetniško delo. A nič od tega ni bilo nič izjemnega – razen delilnika registra. Trik je v tem, da ste previdni posekati pod obremenitvijo in če se to zgodi (lahko podrobneje razložim, če vas zanima), to pomeni, da lahko vstopate bolj agresivno, brez tveganja, da bi padli čez pregib v urniku delovanja. V tistih dneh je obstajal kup popolnih prevajalnikov, obešenih z žreblji in piščalkami, ki so imeli razdeljevalnike registrov, a tega ni mogel storiti nihče drug.

Težava je v tem, da če dodate metode, ki so predmet vstavljanja, povečujete in povečujete območje vstavljanja, nabor uporabljenih vrednosti takoj preseže število registrov in jih morate zmanjšati. Kritična raven običajno nastopi, ko razdelilec obupa in en dober kandidat za razlitje je vreden drugega, prodali boste nekaj na splošno divjih stvari. Vrednost vstavljanja tukaj je, da izgubite del režijskih stroškov, režijskih stroškov za klicanje in shranjevanje, lahko vidite vrednosti znotraj in jih lahko dodatno optimizirate. Stroški vstavljanja so v tem, da se oblikuje veliko število živih vrednosti in če vaš razdelilnik registra zgori več, kot je potrebno, takoj izgubite. Zato ima večina razdeljevalcev težavo: ko vstavljanje prečka določeno črto, se začne vse na svetu krčiti in produktivnost lahko odplakne v stranišče. Tisti, ki izvajajo prevajalnik, dodajo nekaj hevristik: na primer, da prenehajo z vstavljanjem, začenši z neko dovolj veliko velikostjo, saj bodo dodelitve vse uničile. Tako nastane pregib v grafu uspešnosti - vnašaš, vnašaš, zmogljivost počasi raste - in potem bum! – pade dol kot hiter dvig, ker si preveč podložil. Tako je vse delovalo pred pojavom Jave. Java zahteva veliko več vstavljanja, zato sem moral svoj alokator narediti veliko bolj agresiven, da se izravna, namesto da bi se zrušil, in če vstaviš preveč, se začne razlivati, potem pa še vedno pride trenutek »nič več prelivanja«. To je zanimivo opazovanje in prišlo mi je kar od nikoder, ni očitno, a se je dobro izplačalo. Lotil sem se agresivnega vstavljanja in to me je popeljalo tja, kjer zmogljivost Java in C delujeta drug ob drugem. Res sta si blizu – lahko napišem kodo Java, ki je bistveno hitrejša od kode C in podobne stvari, toda v povprečju sta si v veliki sliki stvari približno primerljiva. Mislim, da je del te zasluge dodeljevalec registra, ki mi omogoča čim bolj neumno vstavljanje. Samo vstavim vse, kar vidim. Vprašanje tukaj je, ali alokator deluje dobro, ali je rezultat inteligentno delujoča koda. To je bil velik izziv: razumeti vse to in narediti, da deluje.

Nekaj ​​o dodelitvi registrov in večjedrnih jedrih

Vladimir: Problemi, kot je dodeljevanje registrov, se zdijo nekakšna večna, neskončna tema. Zanima me, ali je že kdaj obstajala ideja, ki se je zdela obetavna, pa je v praksi propadla?

Cliff: Vsekakor! Dodeljevanje registra je področje, na katerem poskušate najti nekaj hevristik za rešitev NP-popolnega problema. In nikoli ne morete doseči popolne rešitve, kajne? To je preprosto nemogoče. Glej, kompilacija Ahead of Time - tudi ta slabo deluje. Pogovor tukaj teče o nekih povprečnih primerih. O tipični zmogljivosti, tako da lahko izmerite nekaj, za kar menite, da je dobra tipična zmogljivost – navsezadnje delate na tem, da bi jo izboljšali! Dodeljevanje registra je tema, ki se nanaša izključno na uspešnost. Ko imate prvi prototip, deluje in pobarva, kar je potrebno, se začne delo izvedbe. Morate se naučiti dobro meriti. Zakaj je pomembno? Če imate jasne podatke, lahko pogledate različna področja in vidite: ja, tukaj je pomagalo, toda tam se je vse zalomilo! Pojavijo se dobre ideje, dodaš nove hevristike in nenadoma začne vse v povprečju delovati malo bolje. Ali pa se ne zažene. Imel sem kup primerov, ko smo se borili za petodstotno uspešnost, ki je naš razvoj razlikovala od prejšnjega delilnika. In vsakič je videti tako: nekje zmagaš, nekje izgubiš. Če imate dobra orodja za analizo uspešnosti, lahko najdete izgubljene ideje in razumete, zakaj ne uspejo. Mogoče je vredno pustiti vse tako, kot je, ali morda resneje pristopiti k natančnemu nastavljanju ali iti ven in popraviti nekaj drugega. To je cel kup stvari! Naredil sem ta kul kramp, vendar potrebujem tudi tega, in tega, in tega - in njihova skupna kombinacija daje nekaj izboljšav. In samotarji lahko spodletijo. To je narava izvedbenega dela na NP-popolnih problemih.

Vladimir: Človek dobi občutek, da so stvari, kot je slikanje v alokatorjih, problem, ki je že rešen. No, zate je odločeno, po tvojem govoru sodeč, ali se potem sploh splača ...

Cliff: Ni razrešeno kot tako. Vi ste tisti, ki ga morate spremeniti v "rešeno". Obstajajo težki problemi in jih je treba rešiti. Ko je to storjeno, je čas za delo na produktivnosti. Temu delu se morate ustrezno posvetiti - narediti primerjalne teste, zbrati metrike, razložiti situacije, ko je vaš stari kramp znova začel delovati (ali obratno, ustavil), ko ste se vrnili na prejšnjo različico. In ne odnehaj, dokler nečesa ne dosežeš. Kot sem že rekel, če obstajajo kul ideje, ki niso delovale, toda na področju dodeljevanja registrov idej je približno neskončno. Lahko na primer berete znanstvene publikacije. Čeprav se je zdaj to področje začelo premikati veliko počasneje in je postalo bolj jasno kot v mladosti. Vendar pa na tem področju dela nešteto ljudi in vse njihove ideje so vredne preizkusa, vse čakajo na svoje. In ne morete reči, kako dobri so, če jih ne poskusite. Kako dobro se integrirajo z vsem drugim v vašem razdeljevalniku, ker razdelilnik počne veliko stvari in nekatere ideje v vašem posebnem razdeljevalniku ne bodo delovale, v drugem razdeljevalniku pa bodo zlahka. Glavni način za zmago za razdeljevalca je, da povleče počasno sranje z glavne poti in ga prisili, da se razdeli vzdolž meja počasnih poti. Torej, če želite zagnati GC, izberite počasno pot, deoptimizirajte, vrzite izjemo, vse te stvari - veste, da so te stvari relativno redke. In res so redki, sem preveril. Opravite dodatno delo in to odstrani veliko omejitev na teh počasnih poteh, vendar to pravzaprav ni pomembno, ker so počasne in redko potujejo. Na primer, ničelni kazalec - to se nikoli ne zgodi, kajne? Za različne stvari morate imeti več poti, vendar ne smejo posegati v glavno. 

Vladimir: Kaj menite o večjedrnih jedrih, ko jih je na tisoče hkrati? Je to uporabna stvar?

Cliff: Uspeh grafičnega procesorja kaže, da je zelo uporaben!

Vladimir: So precej specializirani. Kaj pa procesorji za splošno uporabo?

Cliff: No, to je bil Azulov poslovni model. Odgovor se je vrnil v dobi, ko so ljudje resnično ljubili predvidljivo delovanje. Takrat je bilo težko pisati vzporedno kodo. Model kodiranja H2O je zelo razširljiv, vendar ni model za splošne namene. Morda nekoliko bolj splošno kot pri uporabi GPE. Ali govorimo o kompleksnosti razvoja take stvari ali kompleksnosti uporabe? Na primer, Azul me je naučil zanimivo lekcijo, precej neočitno: majhni zakladi so normalni. 

Največji izziv v življenju

Vladimir: Kaj pa netehnični izzivi?

Cliff: Največji izziv ni bil biti ... prijazen in prijazen do ljudi. In posledično sem se ves čas znašel v izjemno konfliktnih situacijah. Tiste, pri katerih sem vedel, da gredo stvari narobe, vendar nisem vedel, kako naprej s temi težavami in jih nisem mogel obvladati. Na ta način so nastale številne dolgoročne težave, ki trajajo desetletja. Dejstvo, da ima Java prevajalnika C1 in C2, je neposredna posledica tega. Neposredna posledica je tudi dejstvo, da v Javi deset let zapored ni bilo večnivojskega prevajanja. Očitno je, da smo tak sistem potrebovali, ni pa jasno, zakaj ga ni bilo. Imel sem težave z enim inženirjem... ali skupino inženirjev. Nekoč, ko sem začela delati pri Sunu, sem bila ... Dobro, ne samo takrat, na splošno imam vedno o vsem svoje mnenje. In mislil sem, da je res, da lahko preprosto vzameš to svojo resnico in jo poveš v oči. Še posebej, ker sem imel večino časa šokantno prav. In če vam ta pristop ni všeč ... še posebej, če se očitno motite in delate neumnosti ... Na splošno bi malokdo prenesel to obliko komunikacije. Čeprav bi nekateri lahko, kot jaz. Vse življenje sem zgradil na meritokratskih načelih. Če mi pokažeš kaj narobe, se takoj obrnem in rečem: rekel si neumnost. Ob tem se seveda opravičujem in vse to, upošteval bom utemeljenosti, če bodo, in sprejel druge pravilne ukrepe. Po drugi strani pa imam šokantno prav glede šokantno velikega odstotka celotnega časa. In to ne deluje najbolje v odnosih z ljudmi. Ne poskušam biti prijazen, ampak postavljam vprašanje odkrito. "To ne bo nikoli delovalo, ker ena, dva in tri." In bili so kot "Oh!" Bile so še druge posledice, ki jih je bilo verjetno bolje prezreti: na primer tiste, ki so privedle do ločitve od moje žene in desetletne depresije po tem.

Izziv je boj z ljudmi, z njihovim dojemanjem, kaj zmoreš ali ne, kaj je pomembno in kaj ne. Glede sloga kodiranja je bilo veliko izzivov. Še vedno pišem veliko kode in v tistih časih sem moral celo upočasniti, ker sem opravljal preveč vzporednih nalog in jih opravljal slabo, namesto da bi se osredotočil na eno. Če pogledam nazaj, sem napisal polovico kode za ukaz Java JIT, ukaz C2. Naslednji najhitrejši kodirnik je pisal polovico počasneje, naslednji polovico počasneje, in to je bil eksponentni upad. Sedmi v tej vrsti je bil zelo, zelo počasen – to se vedno zgodi! Dotaknil sem se veliko kode. Pogledal sem, kdo je kaj napisal, brez izjeme, strmel sem v njihovo kodo, pregledal vsakega od njih in še vedno sam pisal več kot kdorkoli od njih. Ta pristop pri ljudeh ne deluje najbolje. Nekaterim to ni všeč. In ko ne zmorejo, se začnejo najrazličnejše pritožbe. Enkrat so mi na primer rekli, naj neham kodirati, ker sem pisal preveč kode in je to ogrožalo ekipo, in vse mi je zvenelo kot šala: stari, če preostanek ekipe izgine in jaz še naprej pišem kodo, ti Izgubili bomo samo polovico ekip. Po drugi strani pa, če še naprej pišem kodo in izgubiš polovico ekipe, to zveni kot zelo slabo upravljanje. Nikoli nisem zares razmišljal o tem, nikoli nisem govoril o tem, a je bilo še vedno nekje v moji glavi. V ozadju mojega uma se je vrtela misel: "A me vsi hecate?" Največji problem sem bil torej jaz in moji odnosi z ljudmi. Zdaj se veliko bolje razumem, dolgo časa sem bil vodja ekipe za programerje, zdaj pa ljudem direktno rečem: veste, jaz sem, kar sem, in imeli boste opraviti z mano - ali je v redu, če stojim tukaj? In ko so se s tem začeli ukvarjati, je vse delovalo. Pravzaprav nisem ne slab ne dober, nimam slabih namenov ali sebičnih teženj, to je samo moje bistvo in s tem moram nekako živeti.

Andrew: Pred kratkim so vsi začeli govoriti o samozavedanju introvertiranih in mehkih veščinah nasploh. Kaj lahko rečete o tem?

Cliff: Da, to je bil vpogled in lekcija, ki sem se jo naučil po ločitvi od žene. Od ločitve sem se naučil razumeti samega sebe. Tako sem začel razumeti druge ljudi. Razumeti, kako ta interakcija deluje. To je vodilo do odkritij eno za drugim. Bilo je zavedanje, kdo sem in kaj predstavljam. Kaj počnem: ali sem preobremenjen z nalogo, ali se izogibam konfliktom, ali kaj drugega – in ta stopnja samozavedanja res pomaga, da imam nadzor. Po tem gre vse veliko lažje. Ena stvar, ki sem jo odkril ne samo pri sebi, ampak tudi pri drugih programerji je nezmožnost verbaliziranja misli, ko ste pod čustvenim stresom. Na primer, sedite tam in kodirate, v stanju pretoka, nato pa pritečejo k vam in začnejo histerično kričati, da je nekaj pokvarjeno in da bodo zdaj proti vam sprejeti skrajni ukrepi. In ne morete reči niti besede, ker ste v stanju čustvenega stresa. Pridobljeno znanje vam omogoča, da se pripravite na ta trenutek, ga preživite in preidete na načrt umika, po katerem lahko nekaj storite. Tako da, ko se začnete zavedati, kako vse to deluje, je to velik dogodek, ki vam spremeni življenje. 
Sam nisem našel pravih besed, vendar sem se spomnil zaporedja dejanj. Bistvo je, da je ta reakcija tako fizična kot verbalna in potrebujete prostor. Tak prostor, v zenovskem smislu. Ravno to je treba razložiti, potem pa se takoj umakniti – čisto fizično odmakniti. Ko sem verbalno tiho, lahko čustveno predelam situacijo. Ko adrenalin doseže vaše možgane, vas preklopi v boj ali beg, ne morete več reči ničesar, ne - zdaj ste idiot, inženir bičanja, nesposoben dostojnega odgovora ali celo zaustavitve napada, napadalec pa je na prostosti. napadati znova in znova. Najprej morate spet postati sami, ponovno pridobiti nadzor, izstopiti iz načina »boj ali beg«.

In za to potrebujemo verbalni prostor. Samo prosti prostor. Če sploh kaj rečeš, potem lahko rečeš natanko to, nato pa pojdi in res najdi »prostor« zase: pojdi na sprehod v park, zapri se pod tuš - ni pomembno. Glavna stvar je, da se začasno odklopite od te situacije. Takoj, ko se vsaj za nekaj sekund izklopiš, se vrne nadzor, začneš trezno razmišljati. "V redu, nisem nekakšen idiot, ne počnem neumnosti, sem precej uporabna oseba." Ko ste se uspeli prepričati, je čas, da preidete na naslednjo stopnjo: razumevanje, kaj se je zgodilo. Bili ste napadeni, napad je prišel od tam, kjer ga niste pričakovali, bila je nepoštena, podla zaseda. To je slabo. Naslednji korak je razumeti, zakaj je napadalec to potreboval. Res, zakaj? Morda zato, ker je sam besen? Zakaj je jezen? Na primer, ker se je zajebal in ne more sprejeti odgovornosti? To je način za skrbno ravnanje s celotno situacijo. A to zahteva manevrski prostor, verbalni prostor. Prvi korak je prekinitev verbalnega stika. Izogibajte se pogovoru z besedami. Prekliči, odidi čim prej. Če gre za telefonski pogovor, samo odloži slušalko – to je veščina, ki sem se jo naučil v komunikaciji s svojo bivšo ženo. Če pogovor ne gre dobro, recite "nasvidenje" in odložite slušalko. Z druge strani slušalke: "bla bla bla", vi odgovorite: "ja, adijo!" in odloži slušalko. Samo končajte pogovor. Pet minut kasneje, ko se vam vrne sposobnost razumnega razmišljanja, se malo ohladite, postane mogoče razmišljati o vsem, kar se je zgodilo in kaj se bo zgodilo. In začnite oblikovati premišljen odgovor, namesto da se odzovete zgolj iz čustev. Zame je bil preboj v samozavedanju ravno to, da v primeru čustvenega stresa ne morem govoriti. Izhod iz tega stanja, razmišljanje in načrtovanje, kako se odzvati in kompenzirati težave – to so pravi koraki v primeru, ko ne morete govoriti. Najlažji način je, da pobegnemo iz situacije, v kateri se čustveni stres kaže, in preprosto prenehamo sodelovati v tem stresu. Po tem postaneš sposoben misliti, ko lahko misliš, postaneš sposoben govoriti itd.

Mimogrede, na sodišču vam to poskuša storiti nasprotni odvetnik - zdaj je jasno, zakaj. Ker te ima sposobnost potlačiti do takega stanja, da ne moreš na primer niti izgovoriti svojega imena. V zelo resničnem smislu ne boste mogli govoriti. Če se vam to zgodi in če veste, da se boste znašli na mestu, kjer divjajo besedne bitke, na mestu, kot je sodišče, potem lahko pridete s svojim odvetnikom. Odvetnik se bo zavzel za vas in zaustavil verbalni napad, in to na povsem zakonit način, izgubljeni zenovski prostor pa vam bo povrnjen. Nekajkrat sem moral na primer poklicati svojo družino, sodnica je bila glede tega kar prijazna, nasprotni odvetnik pa je kričal in kričal name, sploh nisem mogel priti do besede. V teh primerih mi najbolj ustreza uporaba mediatorja. Mediator zaustavi ves ta pritisk, ki v neprekinjenem toku zliva nate, najdeš potreben zenovski prostor, s tem pa se vrne sposobnost govora. To je celotno področje znanja, na katerem je treba veliko študirati, marsikaj odkriti v sebi, vse to pa se spremeni v strateške odločitve na visoki ravni, ki so različne za različne ljudi. Nekateri ljudje nimajo zgoraj opisanih težav, navadno jih nimajo ljudje, ki so profesionalni prodajalci. Vsi ti ljudje, ki se preživljajo z besedami – znani pevci, pesniki, verski voditelji in politiki, imajo vedno kaj povedati. Oni nimajo takih težav, jaz pa jih imam.

Andrew: Bilo je ... nepričakovano. Super, veliko sva se že pogovarjala in čas je, da končam ta intervju. Zagotovo se bomo srečali na konferenci in bomo lahko nadaljevali ta dialog. Se vidimo v Hydri!

Pogovor s Cliffom lahko nadaljujete na konferenci Hydra 2019, ki bo 11. in 12. julija 2019 v St. Prišel bo s poročilom "Izkušnja transakcijskega pomnilnika strojne opreme Azul". Vstopnice je mogoče kupiti na uradni spletni strani.

Vir: www.habr.com

Dodaj komentar