Java тіліндегі JIT компиляциясының әкесі Клифф Кликпен тамаша сұхбат

Java тіліндегі JIT компиляциясының әкесі Клифф Кликпен тамаша сұхбатCliff Click — Cratus (процесті жақсартуға арналған IoT сенсорлары), бірнеше сәтті шығулары бар бірнеше стартаптардың (соның ішінде Rocket Realtime School, Neurensic және H2O.ai) негізін қалаушы және тең құрылтайшысы. Клифф өзінің алғашқы компиляторын 15 жасында жазды (TRS Z-80 үшін Паскаль)! Ол Java-дағы C2 (IR түйіндері теңізі) жұмысымен танымал. Бұл компилятор әлемге JIT жоғары сапалы кодты шығара алатынын көрсетті, бұл Java-ның негізгі заманауи бағдарламалық платформалардың бірі ретінде пайда болуының факторларының бірі болды. Содан кейін Cliff Azul Systems компаниясына 864 миллисекунд ішінде 500 гигабайт үймедегі GC үзілістерін қолдайтын таза Java бағдарламалық құралы бар 10 ядролы негізгі фрейм құруға көмектесті. Жалпы, Клифф JVM-тің барлық аспектілерімен жұмыс істей алды.

 
Бұл хабрапост - Клиффпен тамаша сұхбат. Біз келесі тақырыптарда сөйлесетін боламыз:

  • Төмен деңгейлі оңтайландыруларға көшу
  • Үлкен рефакторингті қалай жасауға болады
  • Шығын үлгісі
  • Төмен деңгейлі оңтайландыру тренингі
  • Жұмыс өнімділігін арттырудың практикалық мысалдары
  • Неліктен өзіңіздің бағдарламалау тіліңізді жасаңыз
  • Өнімділік инженері мансабы
  • Техникалық қиындықтар
  • Регистрді бөлу және көп ядролар туралы аздап
  • Өмірдегі ең үлкен сынақ

Сұхбатты жүргізеді:

  • Андрей Сатарин Amazon Web Services сайтынан. Мансап жолында ол мүлдем басқа жобаларда жұмыс істей алды: Яндекс-те NewSQL таратылған деректер базасын, Касперский зертханасында бұлтты анықтау жүйесін, Mail.ru-да көп ойыншы ойынын және Deutsche Bank-те валюта бағасын есептеу қызметін сынады. Кең ауқымды сервер және таратылған жүйелерді сынауға қызығушылық танытады.
  • Владимир Ситников Netcracker сайтынан. Желіні және желілік жабдықты басқару процестерін автоматтандыру үшін байланыс операторлары пайдаланатын NetCracker ОЖ өнімділігі мен ауқымдылығы бойынша он жылдық жұмыс. Java және Oracle Database өнімділік мәселелеріне қызығушылық танытады. Ресми PostgreSQL JDBC драйверінде оннан астам өнімділікті жақсартулардың авторы.

Төмен деңгейлі оңтайландыруларға көшу

Эндрю: Сіз JIT компиляциясы, Java және жалпы өнімділік жұмысы әлеміндегі үлкен атаусыз, солай емес пе? 

Жартас: Дәл солай!

Эндрю: Орындаушылық жұмыс туралы жалпы сұрақтардан бастайық. CPU деңгейінде жұмыс істеу сияқты жоғары деңгейлі және төмен деңгейлі оңтайландырулар арасындағы таңдау туралы не ойлайсыз?

Жартас: Иә, мұнда бәрі қарапайым. Ең жылдам код - ешқашан іске қосылмайтын код. Сондықтан әрқашан жоғары деңгейден бастау керек, алгоритмдермен жұмыс істеу керек. Кейбір жеткілікті үлкен тұрақтылар араласпайынша, жақсырақ O белгісі нашаррақ O белгісін жеңеді. Төменгі деңгейлер соңғы болып қалады. Әдетте, стектің қалған бөлігін жеткілікті түрде оңтайландырған болсаңыз және әлі де қызықты нәрселер қалса, бұл төмен деңгей. Бірақ жоғары деңгейден қалай бастау керек? Жеткілікті жоғары деңгейде жұмыс атқарылғанын қайдан білесіз? Жақсы... мүмкін емес. Дайын рецепттер жоқ. Сіз мәселені түсінуіңіз керек, не істейтініңізді шешіңіз (болашақта қажетсіз қадамдар жасамау үшін), содан кейін пайдалы нәрсе айта алатын профильді ашуға болады. Бір кездері сіз қажетсіз нәрселерден құтылғаныңызды түсінесіз және төмен деңгейлі дәл реттеуді жасайтын уақыт келді. Бұл өнердің ерекше түрі екені сөзсіз. Көптеген адамдар қажет емес нәрселермен айналысады, бірақ тез қозғалатыны сонша, олардың өнімділік туралы алаңдауға уақыты жоқ. Бірақ бұл сұрақ ашық түрде туындағанға дейін. Әдетте, 99% уақыт маңызды нәрсе ешкімге мән бермейтін сыни жолда келе жатқанға дейін, менің не істейтінімді ешкім қызықтырмайды. Міне, бәрі сізді «неге ол ең басынан бастап жақсы жұмыс істемеді» деп ренжіте бастайды. Жалпы алғанда, өнімділікті жақсарту үшін әрқашан бір нәрсе бар. Бірақ 99% жағдайда сізде жетекші болмайды! Сіз жай ғана бірдеңе жұмыс істеуге тырысып жатырсыз және бұл процесте сіз ненің маңызды екенін түсінесіз. Сіз бұл бөліктің мінсіз болуы керек екенін ешқашан алдын ала біле алмайсыз, сондықтан, шын мәнінде, сіз бәрінде мінсіз болуыңыз керек. Бірақ бұл мүмкін емес және сіз мұны жасамайсыз. Әрқашан түзететін көп нәрсе бар - бұл қалыпты жағдай.

Үлкен рефакторингті қалай жасауға болады

Эндрю: Сіз спектакльде қалай жұмыс жасайсыз? Бұл қиылысатын мәселе. Мысалы, бұрыннан бар көптеген функционалдықтардың қиылысуынан туындайтын мәселелермен жұмыс істеуге тура келді ме?

Жартас: Мен одан аулақ болуға тырысамын. Егер өнімділік мәселесі болатынын білсем, кодтауды бастамас бұрын, әсіресе деректер құрылымдарымен бұл туралы ойлаймын. Бірақ көбіне мұның бәрін кейінірек білесің. Содан кейін сіз төтенше шараларға баруыңыз керек және мен «қайта жазу және жеңу» деп атайтын нәрсені істеуіңіз керек: сізге жеткілікті үлкен бөлікті алу керек. Кейбір кодтар өнімділік ақауларына немесе басқа нәрсеге байланысты әлі де қайта жазылуы керек. Кодты қайта жазудың себебі қандай болса да, кішірек бөлікке қарағанда үлкенірек бөлікті қайта жазған дұрыс. Осы кезде бәрі қорқып дірілдей бастайды: «Құдайым, сен сонша кодты ұстай алмайсың!» Бірақ шын мәнінде, бұл тәсіл әрқашан дерлік әлдеқайда жақсы жұмыс істейді. Бірден үлкен мәселені қолға алып, оның айналасына үлкен шеңбер сызып, мынаны айту керек: мен шеңбердің ішіндегі бәрін қайта жазамын. Жиек оның ішіндегі ауыстыруды қажет ететін мазмұннан әлдеқайда аз. Ал егер мұндай шекараларды белгілеу ішкі жұмысты мінсіз орындауға мүмкіндік берсе, қолыңыз бос, қалағаныңызды жасаңыз. Мәселені түсінгеннен кейін, қайта жазу процесі әлдеқайда жеңіл, сондықтан үлкен тістеп алыңыз!
Сонымен қатар, үлкен қайта жазуды орындаған кезде және өнімділік мәселе болатынын түсінгенде, сіз бірден бұл туралы алаңдай бастай аласыз. Бұл әдетте «деректерді көшірмеу, деректерді мүмкіндігінше қарапайым басқару, оны кішірейту» сияқты қарапайым нәрселерге айналады. Үлкен қайта жазуларда өнімділікті жақсартудың стандартты жолдары бар. Және олар әрқашан дерлік деректердің айналасында айналады.

Шығын үлгісі

Эндрю: Подкасттардың бірінде сіз өнімділік контекстіндегі шығындар үлгілері туралы айттыңыз. Мұнымен не айтқыңыз келгенін түсіндіре аласыз ба?

Жартас: Әрине. Мен процессордың өнімділігі өте маңызды болған дәуірде дүниеге келдім. Бұл дәуір қайтадан оралады - тағдыр ирониясыз емес. Мен сегіз разрядты машиналар күндерінде өмір сүре бастадым; менің бірінші компьютерім 256 байтпен жұмыс істеді. Дәл байт. Барлығы өте кішкентай болды. Нұсқауларды санау керек болды, және біз бағдарламалау тілінің стекін жоғары жылжыта бастағанда, тілдер барған сайын күшейе түсті. Assembler болды, содан кейін Basic, содан кейін C және C регистрлерді бөлу және нұсқауларды таңдау сияқты көптеген мәліметтерді қамтыды. Бірақ онда бәрі анық болды, егер мен айнымалының данасына көрсеткіш жасасам, онда мен жүкті аламын және бұл нұсқаулықтың құны белгілі болды. Аппараттық құрал машина циклдерінің белгілі бір санын шығарады, сондықтан әртүрлі заттардың орындалу жылдамдығын сіз іске қосылатын барлық нұсқауларды қосу арқылы жай ғана есептеуге болады. Әрбір салыстыру/сынау/филиал/қоңырау/жүктеу/дүкенді қосуға болады және: бұл сіз үшін орындау уақыты. Өнімділікті жақсарту бойынша жұмыс істегенде, сіз шағын ыстық циклдерге қандай сандар сәйкес келетініне міндетті түрде назар аударасыз. 
Бірақ Java, Python және ұқсас нәрселерге ауысқаннан кейін сіз төмен деңгейлі аппараттық құралдардан тез арада кетесіз. Java-да қабылдаушыға қоңырау шалу қанша тұрады? HotSpot ішіндегі JIT дұрыс болса сызылған, ол жүктеледі, бірақ егер ол мұны жасамаса, бұл функция шақыруы болады. Қоңырау ыстық циклде болғандықтан, ол сол циклдегі барлық басқа оңтайландыруларды қайта анықтайды. Сондықтан нақты құны әлдеқайда жоғары болады. Сіз кодтың бір бөлігін қарау мүмкіндігін бірден жоғалтасыз және оны процессордың тактілік жылдамдығы, жады және пайдаланылған кэш тұрғысынан орындау керек екенін түсінесіз. Мұның бәрі спектакльге шынымен кіріскенде ғана қызықты болады.
Енді біз процессор жылдамдығы он жыл бойына әрең өскен жағдайға тап болдық. Ескі күндер қайта оралды! Сіз енді бір ағынды жақсы өнімділікке сене алмайсыз. Бірақ егер сіз кенеттен параллельді есептеулерге кіріссеңіз, бұл өте қиын, барлығы сізге Джеймс Бонд сияқты қарайды. Мұнда он еселік жеделдету әдетте біреу бірдеңені бұзған жерлерде болады. Сәйкестік көп жұмысты қажет етеді. Бұл XNUMX есе жылдамдату үшін сіз шығын үлгісін түсінуіңіз керек. Бұл не және қанша тұрады? Мұны істеу үшін тілдің негізгі жабдыққа қалай сәйкес келетінін түсіну керек.
Мартин Томпсон өз блогы үшін тамаша сөзді таңдады Механикалық симпатия! Аппараттық құрал не істейтінін, оны қалай дәл орындайтынын және ол бірінші кезекте не істейтінін түсінуіңіз керек. Осыны пайдалана отырып, нұсқауларды санауды және орындау уақытының қайда бара жатқанын анықтауды бастау өте оңай. Егер сізде тиісті дайындық болмаса, сіз қараңғы бөлмеде қара мысықты іздейсіз. Мен үнемі өнімділікті оңтайландыратын адамдарды көремін, олар не істеп жатқанын білмейді. Олар көп зардап шегеді және айтарлықтай алға жылжымайды. Мен бірдей кодты алып, бірнеше кішігірім бұзып, бес немесе он есе жылдамдықты алған кезде, олар: жақсы, бұл әділ емес, біз сенің жақсы екеніңді білдік. Керемет. Мен не туралы айтып отырмын ... шығын үлгісі - бұл сіз қандай кодты жазасыз және ол үлкен суретте орташа есеппен қаншалықты жылдам жұмыс істейді.

Эндрю: Ал сіз мұндай көлемді қалай басыңызда ұстай аласыз? Бұған көбірек тәжірибе арқылы қол жеткізілді ме, әлде? Мұндай тәжірибе қайдан келеді?

Жартас: Мен өз тәжірибемді оңай жолмен алған жоқпын. Мен әр нұсқаулықты түсінуге болатын күндерде Ассамблеяда бағдарламаладым. Бұл ақымақ естіледі, бірақ содан бері Z80 нұсқаулар жинағы әрқашан менің ойымда, жадымда қалды. Сөйлескеннен кейін бір минут ішінде адамдардың есімдері есімде жоқ, бірақ 40 жыл бұрын жазылған код есімде. Бұл күлкілі, бұл синдромға ұқсайды ».ақымақ ғалым«.

Төмен деңгейлі оңтайландыру тренингі

Эндрю: Кірудің оңай жолы бар ма?

Жартас: Иә және жоқ. Біз қолданатын аппараттық құрал уақыт өте көп өзгерген жоқ. Arm смартфондарын қоспағанда, барлығы x86 пайдаланады. Егер сіз қандай да бір қатты ендіруді жасамасаңыз, сіз дәл солай істеп жатырсыз. Жарайды, келесі. Нұсқаулар да ғасырлар бойы өзгерген жоқ. Ассамблеяға барып бірдеңе жазу керек. Көп емес, бірақ түсінуді бастау үшін жеткілікті. Сіз күліп тұрсыз, бірақ мен шындап сөйлеп тұрмын. Сіз тіл мен аппараттық құрал арасындағы сәйкестікті түсінуіңіз керек. Осыдан кейін сіз барып, аздап жазуыңыз керек және кішкентай ойыншық тіліне кішкене ойыншық құрастырушы жасауыңыз керек. Ойыншыққа ұқсас, оны ақылға қонымды уақыт ішінде жасау керек дегенді білдіреді. Бұл өте қарапайым болуы мүмкін, бірақ ол нұсқауларды жасауы керек. Нұсқаулықты құру актісі әр адам жазатын жоғары деңгейлі код пен аппараттық құралда жұмыс істейтін машина коды арасындағы көпірдің шығын үлгісін түсінуге көмектеседі. Бұл корреспонденция компилятор жазылған кезде миға жағылады. Тіпті ең қарапайым компилятор. Осыдан кейін сіз Java-ға және оның семантикалық тұңғиығы әлдеқайда тереңірек екеніне қарай бастай аласыз және оның үстіне көпір салу әлдеқайда қиын. Java тілінде біздің көпіріміз жақсы немесе жаман болды ма, оның құлауына не себеп болатынын және не болмайтынын түсіну әлдеқайда қиын. Бірақ сізге кодты қарап, түсінетін қандай да бір бастапқы нүкте қажет: «иә, бұл қабылдаушы әр уақытта кірістірілген болуы керек». Содан кейін бұл әдіс тым үлкен болған жағдайды қоспағанда, кейде бұл орын алады және JIT бәрін кірістіре бастайды. Мұндай орындардың өнімділігін бірден болжауға болады. Әдетте қабылдағыштар жақсы жұмыс істейді, бірақ содан кейін сіз үлкен ыстық ілмектерге қарап, олардың не істеп жатқанын білмейтін кейбір функционалды шақырулар бар екенін түсінесіз. Бұл гетерлердің кең таралу мәселесі, олардың сызбаға салынбау себебі, олардың гетер екендігі анық емес. Егер сізде өте кішкентай кодтық база болса, оны жай ғана есте сақтай аласыз, содан кейін мынаны айта аласыз: бұл қабылдаушы, ал бұл орнатушы. Үлкен кодтық базада әрбір функция, жалпы алғанда, ешкімге белгісіз өз тарихын өмір сүреді. Профиль жасаушының айтуынша, біз кейбір циклде уақыттың 24% жоғалттық және бұл цикл не істеп жатқанын түсіну үшін ішіндегі әрбір функцияны қарау керек. Функцияны зерттемей, мұны түсіну мүмкін емес және бұл түсіну процесін айтарлықтай баяулатады. Сондықтан мен гетер мен сеттерді қолданбаймын, мен жаңа деңгейге жеттім!
Шығын үлгісін қайдан алуға болады? Жарайды, бірдеңе оқуға болады, әрине... Бірақ менің ойымша, ең дұрысы әрекет ету. Шағын компилятор жасау шығындар үлгісін түсінудің және оны өз басыңызға сәйкестендірудің ең жақсы жолы болады. Микротолқынды пешті бағдарламалау үшін қолайлы шағын компилятор - бұл жаңадан бастағандар үшін тапсырма. Айтайын дегенім, егер сізде бағдарламалау дағдылары болса, бұл жеткілікті болуы керек. Мұның бәрі сізде алгебралық өрнек ретінде бар жолды талдау, сол жерден дұрыс ретпен математикалық операцияларға арналған нұсқауларды алу, регистрлерден дұрыс мәндерді алу - мұның бәрі бірден жасалады. Ал сіз мұны істегенде, ол сіздің миыңызда сақталады. Компилятор не істейтінін бәрі біледі деп ойлаймын. Және бұл шығындар моделі туралы түсінік береді.

Жұмыс өнімділігін арттырудың практикалық мысалдары

Эндрю: Өнімділік бойынша жұмыс істегенде тағы не нәрсеге назар аудару керек?

Жартас: Деректер құрылымдары. Айтпақшы, иә, мен бұл сабақтарды көптен бері оқымадым... Зымыран мектебі. Бұл қызық болды, бірақ көп күш жұмсауды қажет етті, менің де өмірім бар! ЖАРАЙДЫ МА. Сонымен, үлкен және қызықты сабақтардың бірінде «Сіздің өнімділігіңіз қайда кетеді?» Мен студенттерге мысал келтірдім: CSV файлынан екі жарым гигабайт финтех деректері оқылды, содан кейін олар сатылған өнімдердің санын есептеу керек болды. . Тұрақты кене нарығының деректері. UDP пакеттері 70-ші жылдардан бастап мәтіндік форматқа түрлендірілді. Чикаго тауар биржасы - сары май, жүгері, соя, сол сияқты нәрселердің барлық түрлері. Бұл өнімдерді, транзакциялар санын, қаражаттар мен тауарлар қозғалысының орташа көлемін және т.б. санау қажет болды. Бұл өте қарапайым сауда математикасы: өнім кодын табыңыз (хэш кестесінде бұл 1-2 таңба), соманы алыңыз, оны сауда жиындарының біріне қосыңыз, көлемді қосыңыз, құнды қосыңыз және басқа да бірнеше нәрсе. Өте қарапайым математика. Ойыншықты іске асыру өте қарапайым болды: барлығы файлда, мен файлды оқып, онымен қозғалдым, жеке жазбаларды Java жолдарына бөліп, олардан қажетті заттарды іздеп, жоғарыда сипатталған математикаға сәйкес қосамын. Және ол төмен жылдамдықта жұмыс істейді.

Бұл тәсілмен не болып жатқаны анық және параллельді есептеулер көмектеспейді, солай емес пе? Деректер құрылымдарын дұрыс таңдау арқылы өнімділікті бес есе арттыруға болады екен. Бұл тіпті тәжірибелі бағдарламашыларды таң қалдырады! Менің нақты жағдайда, трюк ыстық циклде жадты бөлуді жасамау болды. Бұл шындық емес, бірақ тұтастай алғанда - X жеткілікті үлкен болған кезде «X-да бір рет» белгіленбеу керек. X екі жарым гигабайт болғанда, «әр әріпке бір рет», «әр жолға бір рет» немесе «әр өріске бір рет» сияқты ештеңені бөлуге болмайды. Бұл жерде уақыт жұмсалады. Бұл тіпті қалай жұмыс істейді? Мен қоңырау шалып жатырмын деп елестетіңіз String.split() немесе BufferedReader.readLine(). Readline желі арқылы келген байттардың жиынынан жолды әрбір жол үшін, жүздеген миллион жолдардың әрқайсысы үшін бір рет жасайды. Мен бұл сызықты алып, оны талдап, лақтырып тастаймын. Мен оны неге лақтырып жатырмын - жақсы, мен оны өңдеп қойдым, бәрі осы. Осылайша, осы 2.7G-ден оқылған әрбір байт үшін жолда екі таңба жазылады, яғни қазірдің өзінде 5.4G және маған олардан басқа ештеңе қажет емес, сондықтан олар лақтырылады. Жад өткізу қабілетіне қарасаңыз, біз процессордағы жад пен жад шинасы арқылы өтетін 2.7G жүктейміз, содан кейін жадта жатқан желіге екі есе көп жіберіледі және мұның бәрі әрбір жаңа жолды жасағанда тозып кетеді. Бірақ мен оны оқуым керек, бәрі кейінірек тозған болса да, аппараттық құрал оны оқиды. Мен оны жазуым керек, себебі мен жолды жасадым және кэштер толы - кэш 2.7G сыйдыра алмайды. Сонымен, мен оқыған әрбір байт үшін мен тағы екі байтты оқып, тағы екі байтты жазамын, соңында олардың 4:1 қатынасы бар - бұл қатынаста біз жад өткізу қабілеттілігін жоғалтып жатырмыз. Сосын, егер мен жасасам, солай болып шығады String.split() – Мен мұны соңғы рет жасап тұрғаным жоқ, ішінде тағы 6-7 өріс болуы мүмкін. Осылайша, CSV оқудың классикалық коды, содан кейін жолдарды талдау сіз қалаған жад өткізу қабілеттілігінің шамамен 14:1 бөлігін босқа жібереді. Егер сіз осы таңдауларды тастасаңыз, жылдамдықты бес есе арттыруға болады.

Және бұл соншалықты қиын емес. Егер сіз кодты дұрыс бұрыштан қарасаңыз, мәселені түсінгеннен кейін бәрі қарапайым болады. Сіз жадты бөлуді мүлдем тоқтатпауыңыз керек: жалғыз мәселе - сіз бір нәрсені бөлесіз және ол бірден өледі және жол бойында ол маңызды ресурсты күйдіреді, бұл жағдайда жад өткізу қабілеті. Мұның бәрі өнімділіктің төмендеуіне әкеледі. x86 жүйесінде әдетте процессор циклдерін белсенді түрде жазу керек, бірақ мұнда сіз барлық жадты әлдеқайда ертерек өртеп жібердіңіз. Шешім разрядтың мөлшерін азайту болып табылады. 
Мәселенің басқа бөлігі мынада, егер сіз жад жолағы таусылған кезде профильді іске қоссаңыз, ол орын алған кезде, әдетте кэштің қайтып келуін күтесіз, себебі ол жаңа ғана шығарған қоқысқа толы, барлық жолдар. Сондықтан, әрбір жүктеу немесе дүкен операциясы баяу болады, себебі олар кэшті өткізіп жіберуге әкеледі - бүкіл кэш қоқыстың одан шығуын күтіп, баяу болды. Сондықтан профиль жасаушы бүкіл цикл бойына жағылған жылы кездейсоқ шуды ғана көрсетеді - кодта бөлек ыстық нұсқау немесе орын болмайды. Тек шу. Егер сіз GC циклдарына қарасаңыз, олардың барлығы Жас ұрпақ және өте жылдам – максимум микросекундтар немесе миллисекундтар. Өйткені, бұл жадтың бәрі бірден өледі. Сіз миллиардтаған гигабайт бөлесіз, ол оларды қысқартады, және оларды қысқартады және қайтадан қысқартады. Мұның бәрі өте тез болады. Арзан GC циклдары, бүкіл цикл бойымен жылы шу бар екені белгілі болды, бірақ біз 5 есе жылдамдықты алғымыз келеді. Осы сәтте сіздің басыңызда бірдеңе жабылып, «бұл неге?» Деп естіледі. Жад жолағының толып кетуі классикалық отладчикте көрсетілмейді; сізге аппараттық құрал өнімділігін есептегіш түзету құралын іске қосып, оны өзіңіз және тікелей көруіңіз керек. Бірақ бұл үш симптомнан тікелей күдіктенуге болмайды. Үшінші симптом - сіз бөлектейтін нәрсені қарап, профиль жасаушыдан сұраңыз, ол: «Сіз миллиард жол жасадыңыз, бірақ GC тегін жұмыс істеді» деп жауап береді. Бұл орын алғаннан кейін сіз тым көп нысандар жасап, бүкіл жад жолағын өртеп жібергеніңізді түсінесіз. Мұны анықтаудың жолы бар, бірақ ол анық емес. 

Мәселе деректер құрылымында: барлық болып жатқан нәрсенің негізінде жатқан жалаң құрылым, ол тым үлкен, ол дискіде 2.7G, сондықтан бұл нәрсенің көшірмесін жасау өте қажет емес - оны желілік байт буферінен дереу жүктегіңіз келеді. жолға бес рет алға-артқа оқу-жазбау үшін регистрлерге енгізіңіз. Өкінішке орай, Java сізге әдепкі бойынша JDK бөлігі ретінде мұндай кітапхана бермейді. Бірақ бұл тривиальды, иә? Негізінде, бұл негізгі байт буферінің айналасында орауыш бола отырып, жол сыныбының әрекетін қайталайтын өзіңіздің буферленген жолды жүктеушіңізді іске асыру үшін пайдаланылатын кодтың 5-10 жолы. Нәтижесінде, сіз жолдармен жұмыс істегендей дерлік жұмыс істеп жатырсыз, бірақ іс жүзінде буферге көрсеткіштер сол жерде қозғалады, ал шикі байттар еш жерде көшірілмейді, осылайша бірдей буферлер қайта-қайта пайдаланылады және операциялық жүйе осы байт буферлерінің жасырын қосарланған буферлеуі сияқты өзі әзірленген нәрселерді өзіңізге алуға қуанышты және сіз қажетсіз деректердің шексіз ағыны арқылы бұдан былай ұсақтамайсыз. Айтпақшы, GC-мен жұмыс істегенде, соңғы GC циклінен кейін әрбір жад бөлінісі процессорға көрінбейтініне кепілдік берілетінін түсінесіз бе? Сондықтан мұның бәрі кэште болуы мүмкін емес, содан кейін 100% кепілдік жіберіп алу орын алады. Көрсеткішпен жұмыс істегенде, x86-де, жадтан регистрді алып тастау 1-2 такт циклін алады және бұл орын алғаннан кейін сіз төлейсіз, төлейсіз, төлейсіз, себебі жад барлығы қосулы. ТОҒЫЗ кэш – және бұл жадты бөлу құны. Нақты құн.

Басқаша айтқанда, деректер құрылымдарын өзгерту ең қиын нәрсе. Кейінірек өнімділікті төмендететін қате деректер құрылымын таңдағаныңызды түсінгеннен кейін, әдетте көп жұмыс істеу керек, бірақ олай етпесеңіз, жағдай нашарлайды. Ең алдымен, деректер құрылымдары туралы ойлану керек, бұл маңызды. Мұнда негізгі шығын «Мен X деректер құрылымын Y деректер құрылымына көшірдім, өйткені маған Y пішіні жақсырақ» стилінде қолданыла бастаған майлы деректер құрылымдарына түседі. Бірақ көшіру операциясы (арзан болып көрінеді) іс жүзінде жад өткізу қабілетін ысырап етеді және орындалу уақытының барлығы осы жерде көміледі. Егер менде JSON-ның үлкен жолы болса және оны POJO-лардың құрылымдық DOM ағашына немесе басқа нәрсеге айналдырғым келсе, сол жолды талдау және POJO құру операциясы, содан кейін POJO-ға кейінірек қайта кіру қажетсіз шығындарға әкеледі - бұл арзан емес. Егер сіз POJO айналасында жолды айналып өткеннен гөрі жиірек жүгірсеңіз. Кез келген POJO-ға айналдырмай, оның орнына жолдың шифрын ашуға және одан қажетті нәрсені ғана алуға болады. Егер мұның бәрі максималды өнімділік талап етілетін жолда орын алса, сіз үшін ешқандай POJO жоқ, сіз қандай да бір жолмен тікелей сызықты қазып алуыңыз керек.

Неліктен өзіңіздің бағдарламалау тіліңізді жасаңыз

Эндрю: Шығын үлгісін түсіну үшін өзіңіздің кішкентай тіліңізді жазу керек дедіңіз...

Жартас: Тіл емес, компилятор. Тіл мен компилятор екі түрлі нәрсе. Ең маңызды айырмашылық сіздің басыңызда. 

Эндрю: Айтпақшы, менің білуімше, сіз өз тілдеріңізді жасаумен тәжірибе жасап жатырсыз. Не үшін?

Жартас: Себебі мен аламын! Мен жартылай зейнеткермін, сондықтан бұл менің хоббиім. Мен өмір бойы басқа адамдардың тілдерін енгізумен айналыстым. Мен кодтау стилімде көп жұмыс істедім. Сондай-ақ мен басқа тілдерде проблемаларды көретіндіктен. Мен таныс нәрселерді жасаудың жақсы тәсілдері бар екенін көремін. Ал мен оларды қолданар едім. Мен өзімнен, Java-да, Python-да, кез келген басқа тілде проблемаларды көруден шаршадым. Мен қазір React Native, JavaScript және Elm тілдерінде зейнетке шығу туралы емес, белсенді жұмыс туралы хобби ретінде жазамын. Мен сондай-ақ Python тілінде жазамын және, ең алдымен, Java серверлері үшін машиналық оқытумен жұмыс істеуді жалғастырамын. Көптеген танымал тілдер бар және олардың барлығында қызықты мүмкіндіктер бар. Әркім өзінше жақсы және сіз осы мүмкіндіктердің барлығын біріктіруге тырыса аласыз. Сонымен, мен өзімді қызықтыратын нәрселерді, тілдің мінез-құлқын зерттеймін, ақылға қонымды семантиканы табуға тырысамын. Және әзірге мен жетістікке жеттім! Қазіргі уақытта мен жад семантикасымен күресіп жатырмын, өйткені мен оны C және Java тілдеріндегідей етіп, күшті жад моделін және жүктемелер мен дүкендер үшін жад семантикасын алғым келеді. Сонымен қатар, Haskell сияқты автоматты түрдегі қорытындыға ие болыңыз. Мұнда мен Хаскелл типті тұжырымды C және Java тіліндегі жад жұмысымен араластыруға тырысамын. Мысалы, соңғы 2-3 айда істеп жүрген ісім осы.

Эндрю: Егер сіз басқа тілдерден жақсы жақтарын алатын тіл құрастырсаңыз, біреу керісінше әрекет етеді деп ойлайсыз ба: сіздің идеяларыңызды қабылдап, оларды пайдаланасыз ба?

Жартас: Жаңа тілдер дәл осылай пайда болады! Неліктен Java C тіліне ұқсас? C тілінің барлығы түсінетін жақсы синтаксисі болғандықтан және Java осы синтаксистен шабыттанды, тип қауіпсіздігін, массив шекараларын тексеруді, GC қосады, сонымен қатар олар C тіліндегі кейбір нәрселерді жақсартты. Олар өздерін қосты. Бірақ олар шабыт алды, солай емес пе? Алдыңнан шыққан алыптардың иығында бәрі тұрады – осылайша алға басады.

Эндрю: Менің түсінуімше, сіздің тіліңіз жадта қауіпсіз болады. Сіз Rust-тен несиелік тексеруші сияқты нәрсені енгізу туралы ойладыңыз ба? Сіз оған қарадыңыз ба, ол туралы не ойлайсыз?

Жартас: Мен көптеген жылдар бойы C тілін осы malloc және ақысыз жазып келемін және өмір бойы қолмен басқардым. Білесіз бе, қолмен басқарылатын өмір уақытының 90-95% бірдей құрылымға ие. Ал мұны қолмен жасау өте ауыр. Мен компилятордың сізге бұл жерде не болып жатқанын және сіздің әрекеттеріңізбен неге қол жеткізгеніңізді айтып беруін қалаймын. Кейбір нәрселер үшін қарыз тексерушісі мұны қораптан тыс жасайды. Және ол ақпаратты автоматты түрде көрсетуі керек, бәрін түсінуі керек және тіпті бұл түсінікті ұсынумен ауыртпауы керек. Ол кем дегенде жергілікті қашу талдауын жасауы керек және егер ол сәтсіз болса ғана, өмір сүру уақытын сипаттайтын типтік аннотацияларды қосу керек - және мұндай схема қарызды тексеруге немесе шын мәнінде кез келген жадты тексеруге қарағанда әлдеқайда күрделі. «Бәрі жақсы» және «Мен ештеңе түсінбеймін» арасындағы таңдау - жоқ, жақсырақ нәрсе болуы керек. 
Сондықтан, C тілінде көп код жазған адам ретінде, менің ойымша, өмір бойы автоматты түрде басқаруға қолдау көрсету - ең маңызды нәрсе. Мен сондай-ақ Java-ның қаншалықты жадты пайдаланатынынан шаршадым және негізгі шағым - GC. Жадты Java тілінде бөлгенде, соңғы GC циклінде жергілікті болған жадты қайтармайсыз. Жадты басқару дәлдігі бар тілдерде бұлай емес. Егер сіз malloc-қа қоңырау шалсаңыз, сіз әдетте жаңа ғана пайдаланылған жадты аласыз. Әдетте сіз жадпен уақытша нәрселерді жасайсыз және оны дереу қайтарасыз. Және ол бірден malloc пулына оралады және келесі malloc циклі оны қайтадан шығарады. Демек, нақты жадты пайдалану белгілі бір уақытта тірі нысандар жиынына, сонымен қатар ағып кетуге дейін азаяды. Ал егер бәрі мүлдем әдепсіз түрде ағып кетпесе, жадтың көп бөлігі кэштер мен процессорда аяқталады және ол тез жұмыс істейді. Бірақ дұрыс тәртіпте, дұрыс жерде malloc және тегін шақырылған жадты қолмен басқаруды қажет етеді. Rust мұны өздігінен дұрыс өңдей алады және көп жағдайда одан да жақсы өнімділік береді, өйткені жадты тұтыну ағымдағы есептеуге дейін қысқарады - жадты босату үшін келесі GC циклін күтуге қарағанда. Нәтижесінде біз өнімділікті жақсартудың өте қызықты әдісін алдық. Және өте күшті - мен финтех үшін деректерді өңдеу кезінде осындай нәрселерді жасадым және бұл маған шамамен бес есе жылдамдықты алуға мүмкіндік берді. Бұл өте үлкен серпін, әсіресе процессорлар жылдамдамай жатқан әлемде және біз әлі де жақсартуларды күтеміз.

Өнімділік инженері мансабы

Эндрю: Мен жалпы мансап туралы сұрағым келеді. Сіз HotSpot-те JIT жұмысымен танымал болдыңыз, содан кейін JVM компаниясы болып табылатын Azul-ға көштіңіз. Бірақ біз қазірдің өзінде бағдарламалық жасақтамадан гөрі аппараттық құралдармен көбірек жұмыс жасадық. Содан кейін олар кенеттен Big Data және Machine Learning жүйесіне, содан кейін алаяқтықты анықтауға ауысты. Бұл қалай болды? Бұл дамудың әртүрлі бағыттары.

Жартас: Мен ұзақ уақыт бойы бағдарламалаумен айналысып келемін және көптеген түрлі сабақтарға қатыса алдым. Адамдар: «Ой, сіз Java үшін JIT жасаған адамсыз!» Десе, бұл әрқашан күлкілі. Бірақ бұған дейін мен PostScript клонында жұмыс істедім - Apple бір кездері лазерлік принтерлер үшін қолданған тіл. Ал бұған дейін мен төртінші тілді жүзеге асырдым. Менің ойымша, мен үшін ортақ тақырып - құралдарды әзірлеу. Мен өмір бойы басқа адамдар өздерінің керемет бағдарламаларын жазатын құралдарды жасадым. Бірақ мен операциялық жүйелерді, драйверлерді, ядролық деңгейдегі жөндеушілерді, ОЖ әзірлеуге арналған тілдерді әзірлеуге қатыстым, олар тривиальды басталған, бірақ уақыт өте күрделі болды. Бірақ негізгі тақырып әлі де құралдарды әзірлеу болып табылады. Менің өмірімнің үлкен бөлігі Азул мен Күннің арасында өтті, ол Ява туралы болды. Бірақ мен Big Data және Machine Learning саласына кірген кезде, мен сәнді қалпағымды қайта киіп: «О, қазір бізде маңызды емес мәселе бар, және көптеген қызықты нәрселер болып жатқан және адамдар істеп жатыр» дедім. Бұл дамудың тамаша жолы.

Иә, мен бөлінген есептеулерді жақсы көремін. Менің алғашқы жұмысым жарнамалық жобада С курсының студенті болды. Бұл нақты аналогтық анализатор шығарған аналогтық OCR үшін деректерді жинайтын Zilog Z80 чиптерінде есептеулер таратылды. Бұл керемет және мүлдем ақылсыз тақырып болды. Бірақ проблемалар болды, кейбір бөлігі дұрыс танылмады, сондықтан сіз суретті алып, оны көзімен оқып, не айтқанын хабарлай алатын адамға көрсетуіңіз керек еді, сондықтан деректері бар жұмыстар болды және бұл жұмыстар өз тілі болды. Осының барлығын өңдейтін сервер болды - Z80s vt100 терминалдарымен параллель жұмыс істейді - бір адамға бір, ал Z80-де параллель бағдарламалау моделі болды. Жұлдызша конфигурациясында барлық Z80 құрылғыларымен ортақ жадтың кейбір ортақ бөлігі; Артқы панель де ортақ болды, ал ЖЖҚ жартысы желі ішінде бөлісілді, ал қалған жартысы жеке немесе басқа нәрсеге кетті. Ортақ... жартылай ортақ жады бар мағыналы күрделі параллель бөлінген жүйе. Бұл қашан болды... Тіпті есімде де жоқ, 80-жылдардың ортасында. Біраз уақыт бұрын. 
Иә, 30 жыл өте ұзақ уақыт болды делік.Таратылған есептеулерге байланысты мәселелер бұрыннан бар, адамдар бұрыннан соғысуда. Beowulf- кластерлер. Мұндай кластерлер мынаған ұқсайды... Мысалы: Ethernet бар және сіздің жылдам x86 осы Ethernet желісіне қосылған, енді сіз жалған ортақ жад алғыңыз келеді, өйткені ол кезде ешкім таратылған есептеулерді кодтауды жасай алмады, бұл өте қиын болды, сондықтан бар. x86 жады беттерімен жалған ортақ жад болды және егер сіз осы бетке жазсаңыз, біз басқа процессорларға егер олар бірдей ортақ жадқа қол жеткізсе, оны сізден жүктеу керек екенін айттық, осылайша қолдау көрсету протоколы сияқты нәрсе. кэш когеренттілігі және бұл үшін бағдарламалық қамтамасыз ету пайда болды. Қызықты тұжырымдама. Нағыз мәселе, әрине, басқа нәрседе болды. Мұның бәрі жұмыс істеді, бірақ сіз өнімділік мәселелеріне тез тап болдыңыз, өйткені өнімділік үлгілерін жеткілікті деңгейде ешкім түсінбеді - жадқа қол жеткізудің қандай үлгілері бар, түйіндердің бір-біріне шексіз пинг жасамайтындығына қалай көз жеткізу керек және т.б.

Мен H2O-да ойлап тапқаным, параллелизмнің қайда жасырылғанын және қай жерде жоқ екенін анықтауға әзірлеушілердің өздері жауапты. Мен өнімділігі жоғары кодты жазуды жеңіл және қарапайым ететін кодтау үлгісін ойлап таптым. Бірақ баяу жұмыс істейтін кодты жазу қиын, ол нашар көрінеді. Сізге баяу кодты жазуға тырысу керек, стандартты емес әдістерді қолдануға тура келеді. Тежеу коды бірінші көзқараста көрінеді. Нәтижесінде сіз әдетте жылдам жұмыс істейтін кодты жазасыз, бірақ ортақ жад жағдайында не істеу керектігін анықтауыңыз керек. Мұның бәрі үлкен массивтерге байланысты және ондағы мінез-құлық параллель Java-дағы тұрақты емес үлкен массивтерге ұқсас. Менің айтайын дегенім, екі ағын параллельді массивке жазады деп елестетіңіз, олардың біреуі жеңеді, ал екіншісі сәйкесінше жеңіледі және сіз қайсысының қайсысы екенін білмейсіз. Егер олар өзгермелі болмаса, онда тапсырыс сіз қалаған нәрсе болуы мүмкін - және бұл өте жақсы жұмыс істейді. Адамдар шын мәнінде операциялардың тәртібіне мән береді, олар құбылмалы заттарды дұрыс орындарға қояды және жадқа қатысты өнімділік мәселелерін дұрыс жерлерде күтеді. Әйтпесе, олар жай ғана кодты 1-ден N-ге дейінгі циклдар түрінде жазады, мұнда N - бірнеше триллиондар, барлық күрделі жағдайлар автоматты түрде параллель болады деген үмітпен - және ол жұмыс істемейді. Бірақ H2O-да бұл Java да, Scala да емес; қаласаңыз, оны «Java минус минус» деп санауға болады. Бұл өте айқын бағдарламалау стилі және циклдар мен массивтермен қарапайым C немесе Java кодын жазуға ұқсас. Бірақ сонымен бірге жадты терабайтпен өңдеуге болады. Мен әлі де H2O қолданамын. Мен оны мезгіл-мезгіл әртүрлі жобаларда қолданамын - бұл бәрібір ең жылдам нәрсе, бәсекелестерінен ондаған есе жылдам. Үлкен деректерді бағаналы деректермен орындасаңыз, H2O-ны жеңу өте қиын.

Техникалық қиындықтар

Эндрю: Сіздің мансабыңыздағы ең үлкен қиындық не болды?

Жартас: Біз мәселенің техникалық немесе техникалық емес бөлігін талқылап жатырмыз ба? Ең үлкен қиындықтар техникалық емес деп айтар едім. 
Техникалық қиындықтарға келетін болсақ. Мен оларды жай ғана жеңдім. Ең үлкені не екенін білмеймін, бірақ біраз уақытты, ақыл-ой күресін қажет ететін өте қызықтылары болды. Мен Sun-ға барғанымда, мен тез компилятор жасайтыныма сенімді болдым, ал бір топ үлкендер жауап ретінде ешқашан табысқа жете алмайтынымды айтты. Бірақ мен осы жолмен жүрдім, тізілімді бөлушіге компилятор жаздым және ол өте жылдам болды. Ол қазіргі заманғы C1 сияқты жылдам болды, бірақ ол кезде бөлгіш әлдеқайда баяу болды, ал кейінірек бұл деректер құрылымының үлкен мәселесі болды. Бұл маған графикалық регистрдің бөлгішін жазу үшін қажет болды және мен кодтың экспрессивтілігі мен жылдамдығы арасындағы дилемманы түсінбедім, ол сол дәуірде болған және өте маңызды болды. Деректер құрылымы әдетте сол кездегі x86s кэш өлшемінен асып түсетіні белгілі болды, сондықтан мен бастапқыда регистрлер бөлгіші жалпы діріл уақытының 5-10 пайызын жұмыс істейді деп болжаған болсам, онда шын мәнінде ол болды. 50 пайыз.

Уақыт өте келе компилятор таза және тиімдірек болды, көп жағдайларда қорқынышты код жасауды тоқтатты және өнімділік барған сайын C компиляторы шығаратын нәрсеге ұқсай бастады.Егер, әрине, C тілі де жылдамдамайтындай әбестік жазбасаңыз. . Егер сіз C сияқты кодты жазсаңыз, көп жағдайда C сияқты өнімділікке ие боласыз. Әрі қарай барған сайын, асимптоталық түрде С деңгейіне сәйкес келетін кодты жиі алсаңыз, тізілімді бөлуші кодыңыздың жылдам немесе баяу жұмыс істейтініне қарамастан, толық нәрсе сияқты көріне бастады. Жақсырақ таңдау жасау үшін бөлушіде жұмыс істеуді жалғастырдым. Ол баяу және баяу болды, бірақ ол басқа ешкім жеңе алмайтын жағдайларда жақсырақ және жақсы нәтиже көрсетті. Мен тізілімді бөлушіге кіріп, бір ай жұмысымды көміп тастадым, кенеттен бүкіл код 5% жылдамырақ орындала бастайды. Бұл уақыт өте келе болды және тізілімді бөлуші өнер туындысына айналды - бәрі оны жақсы көрді немесе жек көрді, ал академиядағылар «неге бәрі осылай жасалады» деген тақырыпта сұрақтар қойды. сызықты сканерлеу, ал айырмашылығы неде. Жауап бұрынғысынша: графикті бояуға негізделген бөлгіш және буферлік кодпен өте мұқият жұмыс істеу жеңіс қаруына тең, ешкім жеңе алмайтын ең жақсы комбинация. Және бұл анық емес нәрсе. Құрастырушы жасайтын барлық нәрсе жақсы зерттелген, бірақ олар да өнер деңгейіне жеткізілді. Мен әрқашан құрастырушыны өнер туындысына айналдыруы керек нәрселерді жасадым. Бірақ мұның ешқайсысы ерекше ештеңе болған жоқ - тізілімді бөлушіден басқа. Бұның айласы – сақ болу қысқарту жүктеме астында және, егер бұл орын алса (қызықтырса, мен егжей-тегжейлі түсіндіре аламын), бұл өнімділік кестесіндегі бұрмалану қаупінсіз агрессивті кірістіру мүмкіндігін білдіреді. Сол кездерде тізбелер мен ысқырықтар ілінген, регистрлерді бөлушілері бар толық масштабты құрастырушылар болды, бірақ оны басқа ешкім жасай алмады.

Мәселе мынада, егер сіз кірістіру аймағын ұлғайтуға және ұлғайтуға жататын әдістерді қоссаңыз, пайдаланылған мәндер жиынтығы регистрлердің санынан бірден асып түседі және сіз оларды кесуіңіз керек. Сыни деңгей әдетте бөлгіш бас тартқан кезде келеді және төгілу үшін бір жақсы үміткер басқаға тұрарлық, сіз жалпы жабайы заттарды сатасыз. Мұнда кірістірудің мәні мынада: сіз қоңырау шалу және сақтау үшін үстеме шығындардың бір бөлігін жоғалтасыз, ішіндегі мәндерді көре аласыз және оларды одан әрі оңтайландыра аласыз. Кірістіру құны - тірі мәндердің үлкен саны қалыптасады және тізілімді бөлуші қажеттен көп күйіп кетсе, сіз бірден жоғалтасыз. Сондықтан, үлестіргіштердің көпшілігінде мәселе бар: кірістіру белгілі бір сызықты кесіп өткенде, әлемдегі барлық нәрсе қысқартыла бастайды және өнімділікті дәретханаға төгуге болады. Компиляторды жүзеге асыратындар кейбір эвристиканы қосады: мысалы, кейбір жеткілікті үлкен өлшемнен бастап кірістіруді тоқтату үшін, өйткені бөлу бәрін бұзады. Осылай өнімділік графигіндегі бұрыс пайда болады - сіз кірістірілген, кірістірілген, өнімділік баяу өседі - содан кейін бум! – тым көп сап түзегендіктен жылдам домкрат сияқты құлап қалады. Java пайда болғанға дейін бәрі осылай жұмыс істеді. Java көбірек кірістіруді қажет етеді, сондықтан мен бөлгішті әлдеқайда агрессивті етіп жасауым керек болды, сондықтан ол бұзылудан гөрі деңгейге жетеді, ал егер сіз тым көп кірістіріп алсаңыз, ол төгіле бастайды, бірақ содан кейін «бұдан әрі төгілмейтін» сәт әлі де келеді. Бұл қызықты байқау және ол маған күтпеген жерден келді, анық емес, бірақ ол жақсы нәтиже берді. Мен агрессивті кірістірумен айналыстым және ол мені Java және C өнімділігі қатар жұмыс істейтін жерлерге апарды. Олар өте жақын – мен Java кодын C кодынан және сол сияқты нәрселерден айтарлықтай жылдам жаза аламын, бірақ орта есеппен заттардың үлкен суретінде олар шамамен салыстырмалы. Менің ойымша, бұл еңбектің бір бөлігі - тізілімді бөлуші, ол маған мүмкіндігінше ақымақ кірісуге мүмкіндік береді. Мен көргендердің барлығын ғана кірістіремін. Бұл жерде сұрақ бөлгіш жақсы жұмыс істей ме, нәтиже ақылды жұмыс істейтін код па. Бұл үлкен сынақ болды: мұның бәрін түсіну және оны жүзеге асыру.

Регистрді бөлу және көп ядролар туралы аздап

Владимир: Регистрлерді бөлу сияқты мәселелер мәңгілік, шексіз тақырып сияқты көрінеді. Қызық, болашағы зор болып көрінген, кейін іс жүзінде сәтсіздікке ұшыраған идея болды ма?

Жартас: Әрине! Тізілімді бөлу - NP-толық мәселені шешу үшін кейбір эвристиканы табуға тырысатын аймақ. Сіз ешқашан тамаша шешімге жете алмайсыз, солай емес пе? Бұл жай ғана мүмкін емес. Қараңыз, Ahead of Time компиляциясы - ол да нашар жұмыс істейді. Мұнда әңгіме кейбір орташа жағдайлар туралы. Әдеттегі өнімділік туралы, сондықтан сіз жақсы типтік өнімділік деп ойлайтын нәрсені өлшей аласыз - ақыр соңында сіз оны жақсарту үшін жұмыс істеп жатырсыз! Тіркеуді бөлу - бұл өнімділікке қатысты тақырып. Сізде бірінші прототип болғаннан кейін ол жұмыс істейді және қажет нәрсені бояйды, орындау жұмысы басталады. Жақсы өлшеуді үйрену керек. Неліктен маңызды? Егер сізде нақты деректер болса, сіз әртүрлі аймақтарды қарап, көре аласыз: иә, бұл жерде көмектесті, бірақ бәрі бұзылған жерде! Кейбір жақсы идеялар пайда болады, сіз жаңа эвристика қосасыз және кенеттен бәрі орташа есеппен сәл жақсырақ жұмыс істей бастайды. Немесе ол басталмайды. Менде біздің дамуымызды бұрынғы бөлушіден ерекшелендіретін бес пайыздық өнімділік үшін күрескен көптеген жағдайлар болды. Әр жолы былай көрінеді: бір жерде ұтасың, бір жерде ұтыласың. Егер сізде өнімділікті талдаудың жақсы құралдары болса, сіз жоғалған идеяларды таба аласыз және олардың неге сәтсіздікке ұшырағанын түсіне аласыз. Мүмкін, бәрін сол күйінде қалдыру керек шығар, немесе дәлірек реттеуге неғұрлым байыпты көзқараспен қарауға немесе сыртқа шығып, басқа нәрсені түзетуге тұрарлық. Бұл көп нәрсе! Мен бұл тамаша хакімді жасадым, бірақ маған мынау керек, мынау және мынау керек - және олардың жалпы комбинациясы кейбір жақсартулар береді. Ал жалғыздар сәтсіздікке ұшырауы мүмкін. Бұл NP-толық есептер бойынша өнімділік жұмысының сипаты.

Владимир: Бөлгіштерде сурет салу сияқты нәрселер қазірдің өзінде шешілген мәселе екенін сезінеді. Айтпақшы, бұл сіз үшін шешілді, сіздің айтқаныңызға қарағанда, ол кезде оған тұрарлық па...

Жартас: Ол осылай шешілмейді. Сіз оны «шешілгенге» айналдыруыңыз керек. Күрделі мәселелер бар және оларды шешу қажет. Бұл орындалғаннан кейін өнімділікке жұмыс істеу уақыты келді. Сіз бұл жұмысқа сәйкес келуіңіз керек - салыстыруларды жасаңыз, көрсеткіштерді жинаңыз, алдыңғы нұсқаға оралған кезде, ескі бұзу қайта жұмыс істей бастағанда (немесе керісінше, тоқтаған) жағдайларды түсіндіріңіз. Және бір нәрсеге қол жеткізбейінше берілмеңіз. Жоғарыда айтқанымдай, егер жұмыс істемейтін керемет идеялар болса, бірақ идеялар тізілімдерін бөлу саласында бұл шамамен шексіз. Сіз, мысалы, ғылыми басылымдарды оқи аласыз. Қазір бұл аймақ жас кезіндегіге қарағанда әлдеқайда баяу қозғала бастады және айқынырақ болды. Дегенмен, бұл салада жұмыс істейтін адамдар бар және олардың барлық идеялары сынауға тұрарлық, олардың барлығы қанатында күтуде. Сіз оларды сынап көрмесеңіз, олардың қаншалықты жақсы екенін айта алмайсыз. Олар бөлгіштідегі барлық басқа нәрселермен қаншалықты жақсы біріктірілген, өйткені бөлгіш көп нәрсені жасайды және кейбір идеялар сіздің нақты бөлгіште жұмыс істемейді, бірақ басқа бөлгіште олар оңай жұмыс істейді. Бөлгіш үшін жеңіске жетудің негізгі жолы - баяу заттарды негізгі жолдың сыртына шығару және оны баяу жолдардың шекаралары бойынша бөлуге мәжбүрлеу. Сондықтан, егер сіз GC іске қосқыңыз келсе, баяу жолды ұстаныңыз, оптимизациясыз, ерекшелік тастаңыз, мұның бәрі - бұл нәрселер салыстырмалы түрде сирек кездесетінін білесіз. Және олар өте сирек кездеседі, мен тексердім. Сіз қосымша жұмыс жасайсыз және бұл баяу жолдардағы көптеген шектеулерді алып тастайды, бірақ бұл маңызды емес, өйткені олар баяу және сирек саяхаттайды. Мысалы, нөлдік көрсеткіш - бұл ешқашан болмайды, солай ма? Әртүрлі нәрселер үшін бірнеше жолдар болуы керек, бірақ олар негізгіге кедергі болмауы керек. 

Владимир: Бір уақытта мыңдаған ядролар болғанда, көп ядролар туралы не ойлайсыз? Бұл пайдалы нәрсе ме?

Жартас: GPU табысы оның өте пайдалы екенін көрсетеді!

Владимир: Олар өте мамандандырылған. Жалпы мақсаттағы процессорлар туралы не деуге болады?

Жартас: Бұл Азулдың бизнес үлгісі еді. Жауап адамдар болжамды өнімділікті шынымен жақсы көретін дәуірде оралды. Ол кезде параллель код жазу қиын болды. H2O кодтау үлгісі жоғары масштабталады, бірақ ол жалпы мақсаттағы модель емес. Мүмкін, GPU пайдаланғанға қарағанда біршама жалпы. Біз мұндай нәрсені дамытудың күрделілігі немесе оны пайдаланудың күрделілігі туралы айтып отырмыз ба? Мысалы, Азул маған қызықты сабақ берді, бұл өте айқын емес: кішкентай кэштер қалыпты жағдай. 

Өмірдегі ең үлкен сынақ

Владимир: Техникалық емес қиындықтар туралы не деуге болады?

Жартас: Ең үлкен қиындық - адамдарға мейірімді және жақсы болмау болды. Нәтижесінде мен өзімді үнемі өте қақтығыс жағдайларына тап болдым. Мен жағдайдың дұрыс емес екенін білетін, бірақ бұл проблемаларды қалай шешуге болатынын білмеген және оларды жеңе алмайтын адамдар. Ондаған жылдарға созылған көптеген ұзақ мерзімді проблемалар осылайша пайда болды. Java-да C1 және C2 компиляторлары бар екендігі осының тікелей салдары болып табылады. Он жыл қатарынан Java-да көп деңгейлі компиляция болмағаны да тікелей салдар болып табылады. Мұндай жүйе бізге керек екені анық, бірақ оның неліктен болмағаны түсініксіз. Менде бір инженермен... немесе инженерлер тобымен проблемалар болды. Бір кездері мен Sun-да жұмыс істей бастағанда, мен... Жарайды, тек сол кезде ғана емес, менде әрқашан әр нәрсеге өз пікірім бар. Мен бұл шындықты қабылдап, оны тікелей айта алатыныңыз рас деп ойладым. Әсіресе, мен көп жағдайда таңқаларлықтай дұрыс болдым. Ал егер сізге бұл тәсіл ұнамаса... әсіресе қателесіп, бос сөз істеп жатсаңыз... Жалпы алғанда, қарым-қатынастың бұл түріне аз адам шыдай алады. Кейбіреулер мен сияқты мүмкін болса да. Мен бүкіл өмірімді меритократиялық принциптерге құрдым. Маған дұрыс емес нәрсені көрсетсең, мен бірден бұрылып айтамын: бос сөз айттың. Бұл ретте, әрине, кешірім сұраймын және мұның барлығын, егер бар болса, жақсы жақтарын атап өтіп, басқа да дұрыс әрекеттерді жасаймын. Екінші жағынан, мен жалпы уақыттың таңқаларлық үлкен пайызы туралы таңқаларлықтай дұрыспын. Және бұл адамдармен қарым-қатынаста жақсы жұмыс істемейді. Мен жақсы болуға тырыспаймын, бірақ мен сұрақты ашық қойып отырмын. «Бұл ешқашан жұмыс істемейді, өйткені бір, екі және үш». Және олар: «Ой!» Басқа салдарлар болды, бәлкім, елемеу керек еді: мысалы, менің әйеліммен ажырасуға және одан кейінгі он жыл депрессияға әкелген салдарлар.

Сынақ - бұл адамдармен күрес, олардың сіз не істей алатыныңызды немесе жасай алмайтыныңызды, ненің маңызды және ненің болмайтынын түсінуімен. Кодтау стилінде көптеген қиындықтар болды. Мен әлі де көп код жазамын, сол күндері тіпті баяулауыма тура келді, өйткені мен тым көп параллель тапсырмаларды орындадым және бір нәрсеге назар аударудың орнына оларды нашар орындадым. Өткенге қарасам, Java JIT пәрмені, C2 командасы үшін кодтың жартысын жаздым. Келесі ең жылдам кодер жартысы баяу, келесі жартысы баяу деп жазды және бұл экспоненциалды құлдырау болды. Бұл қатардағы жетінші адам өте баяу болды - бұл әрқашан болады! Мен көп кодты ұстадым. Мен кімнің не жазғанын қарап шықтым, мен олардың кодтарына қарап, олардың әрқайсысына шолу жасадым және олардың кез келгеніне қарағанда өзім жазуды жалғастырдым. Бұл тәсіл адамдармен жақсы жұмыс істемейді. Кейбір адамдарға бұл ұнамайды. Ал олар көтере алмаған соң түрлі шағымдар басталады. Мысалы, бір рет маған кодтауды тоқтатуды айтты, өйткені мен тым көп код жазып едім және бұл командаға қауіп төндірді, және мұның бәрі маған әзіл сияқты көрінді: досым, егер команданың қалған бөлігі жоғалып кетсе және мен кодты жаза берсем, сен Командалардың жартысы ғана жоғалады. Екінші жағынан, егер мен кодты жазуды жалғастырсам және сіз команданың жартысын жоғалтсаңыз, бұл өте нашар басқару сияқты көрінеді. Мен бұл туралы ешқашан ойлаған емеспін, бұл туралы ешқашан айтқан емеспін, бірақ ол әлі де менің бір жерде болды. «Бәрің мені қалжыңдап тұрсың ба?» деген ой санамда айналды. Сондықтан ең үлкен мәселе мен және адамдармен қарым-қатынасым болды. Енді мен өзімді әлдеқайда жақсы түсінемін, мен ұзақ уақыт бойы бағдарламашылар тобының жетекшісі болдым, енді адамдарға тікелей айтамын: мен кіммін, менімен күресуге тура келеді - мен тұрсам жақсы ма? Мұнда? Ал олар онымен айналыса бастағанда, бәрі жұмыс істеді. Шындығында, мен жаман да емеспін, жақсы да емеспін, менде ешқандай жаман ниет немесе өзімшіл ұмтылыстар жоқ, бұл жай ғана менің мәнім, мен онымен қалай да өмір сүруім керек.

Эндрю: Жақында барлығы интроверттердің өзін-өзі тану және жалпы жұмсақ дағдылар туралы айта бастады. Бұл туралы не айта аласыз?

Жартас: Иә, бұл менің әйелімнен ажырасқаннан алған түсінігім және сабақ болды. Ажырасудан білгенім өзімді түсіну болды. Мен басқа адамдарды осылай түсіне бастадым. Бұл әрекеттесу қалай жұмыс істейтінін түсініңіз. Бұл бірінен соң бірі ашылуларға әкелді. Менің кім екенімді және нені білдіретінімді түсіну болды. Мен не істеп жатырмын: не тапсырмамен айналысамын, не жанжалдан аулақпын, немесе басқа нәрсе - және бұл өзін-өзі тану деңгейі өзімді бақылауда ұстауға көмектеседі. Осыдан кейін бәрі оңайырақ болады. Мен өзімнен ғана емес, басқа бағдарламашылардан да байқағаным, эмоционалды күйзеліс кезінде ойды ауызша жеткізе алмау. Мысалы, сіз сол жерде кодтап жатырсыз, ағым күйінде, содан кейін олар сізге жүгіріп келіп, бірдеңе бұзылды, енді сізге қарсы төтенше шаралар қолданылады деп истерикамен айқайлай бастайды. Сіз бір сөз айта алмайсыз, өйткені сіз эмоционалды күйзеліс жағдайындасыз. Алынған білім сізге осы сәтке дайындалуға, одан аман өтуге және шегіну жоспарына өтуге мүмкіндік береді, содан кейін сіз бірдеңе жасай аласыз. Иә, мұның бәрі қалай жұмыс істейтінін түсіне бастағанда, бұл өмірді өзгертетін үлкен оқиға. 
Мен өзім дұрыс сөз таба алмадым, бірақ іс-әрекеттер ретін есіме түсірдім. Мәселе мынада, бұл реакция сөздік сияқты физикалық және сізге кеңістік қажет. Мұндай кеңістік, дзен мағынасында. Дәл осыны түсіндіру керек, содан кейін бірден шетке шығыңыз - таза физикалық түрде кетіңіз. Мен ауызша үндемесем, жағдайды эмоционалды түрде өңдей аламын. Адреналин миыңызға жетіп, сізді ұрыс немесе ұшу режиміне ауыстырған кезде, сіз бұдан былай ештеңе айта алмайсыз, жоқ - енді сіз ақымақсыз, қамшы инженерсіз, лайықты жауап беруге немесе тіпті шабуылды тоқтатуға қабілетсізсіз , ал шабуылдаушы бос қайта-қайта шабуыл жасау. Сіз алдымен өзіңізге айналуыңыз керек, бақылауды қалпына келтіріп, «жекпе-жек немесе ұшу» режимінен шығуыңыз керек.

Ал бұл үшін бізге сөздік кеңістік қажет. Тек бос орын. Егер сіз бірдеңе десеңіз, дәл осылай айта аласыз, содан кейін барып, өзіңіз үшін «кеңістік» табыңыз: саябақта серуендеңіз, душқа кіріңіз - бұл маңызды емес. Ең бастысы, ол жағдайдан уақытша ажырату. Сіз кем дегенде бірнеше секундқа өшірілген кезде, басқару қайта оралады, сіз байсалды ойлай бастайсыз. «Жарайды, мен ақымақ емеспін, мен ақымақтық жасамаймын, мен өте пайдалы адаммын». Сіз өзіңізді сендіре алғаннан кейін, келесі кезеңге өту уақыты келді: не болғанын түсіну. Сізге шабуыл жасалды, шабуыл сіз күтпеген жерден келді, бұл адал емес, арам пиғыл болды. Бұл жаман. Келесі қадам - ​​бұл шабуылдаушыға не үшін қажет екенін түсіну. Шын мәнінде неге? Мүмкін оның өзі ашуланғандықтан ба? Ол неге жынды? Мысалы, ол өзін-өзі бұзып, жауапкершілікті мойнына алмағандықтан ба? Бұл бүкіл жағдайды мұқият өңдеудің жолы. Бірақ бұл үшін маневр, сөздік кеңістік қажет. Ең бірінші қадам - ​​ауызша байланысты үзу. Сөзбен талқылаудан аулақ болыңыз. Оны тоқтатыңыз, мүмкіндігінше тезірек кетіңіз. Егер бұл телефонмен сөйлесу болса, телефонды қоя тұрыңыз - бұл менің бұрынғы әйеліммен сөйлесуден үйренген дағдым. Әңгіме жақсылыққа апармаса, жай ғана «қош бол» деп телефонды өшіріңіз. Телефонның арғы жағынан: «бла бла бла», сіз: «иә, сау бол!» деп жауап бересіз. және трубканы қойыңыз. Сіз жай ғана әңгімені аяқтаңыз. Бес минуттан кейін, ақылға қонымды ойлау қабілеті сізге қайтып келгенде, сіз аздап суыдыңыз, барлығы туралы, не болғанын және не болатынын ойлауға болады. Жәй ғана эмоциядан емес, ойластырылған жауап беруді бастаңыз. Мен үшін өзін-өзі танудағы серпіліс эмоционалды күйзеліс жағдайында сөйлей алмайтындығым болды. Бұл жағдайдан шығу, мәселені қалай шешуге болатынын ойлау және жоспарлау - бұл сіз сөйлей алмаған жағдайда дұрыс қадамдар. Ең оңай жолы - эмоционалды күйзеліс пайда болған жағдайдан қашу және бұл күйзеліске қатысуды тоқтату. Осыдан кейін сіз ойлай аласыз, ойлай алсаңыз, сіз сөйлей аласыз және т.б.

Айтпақшы, сотта қарсылас адвокат сізге мұны істеуге тырысады - енді неге екені түсінікті. Өйткені ол сізді, мысалы, атыңызды айта алмайтындай күйге дейін басу мүмкіндігіне ие. Нақты мағынада сіз сөйлей алмайсыз. Егер сізде осындай жағдай орын алса және сіз өзіңізді ауызша ұрыс-керіс болып жатқан жерде, сот сияқты жерде болатыныңызды білсеңіз, онда сіз адвокатыңызбен келе аласыз. Адвокат сізге қарсы тұрып, ауызша шабуылды тоқтатады және оны толығымен заңды түрде жасайды, ал жоғалған Zen кеңістігі сізге оралады. Мысалы, мен отбасыма бірнеше рет қоңырау шалуға тура келді, судья бұл туралы өте мейірімді болды, бірақ қарсы адвокат айқайлап, маған айқайлады, мен тіпті бір ауыз сөз де алмадым. Мұндай жағдайларда медиаторды пайдалану мен үшін жақсы нәтиже береді. Медиатор сізге үздіксіз ағынмен құйылып жатқан осы қысымның барлығын тоқтатады, сіз қажетті Zen кеңістігін табасыз және онымен сөйлесу мүмкіндігі қайтарылады. Бұл білімнің тұтас саласы, онда зерттелетін, өз бойыңызда ашатын көп нәрсе бар және мұның барлығы әртүрлі адамдар үшін әртүрлі жоғары деңгейдегі стратегиялық шешімдерге айналады. Кейбір адамдарда жоғарыда сипатталған проблемалар жоқ; әдетте, кәсіби сатушы адамдарда олар болмайды. Сөзбен күн көріп отырған бұл адамдардың барлығы – атақты әншілер, ақындар, дін көшбасшылары мен саясаткерлердің айтары бар. Оларда мұндай проблемалар жоқ, бірақ менде бар.

Эндрю: Бұл... күтпеген жерден болды. Керемет, біз көп сөйлестік және бұл сұхбатты аяқтайтын кез келді. Біз конференцияда міндетті түрде кездесеміз және бұл диалогты жалғастыра аламыз. Гидрада кездескенше!

Сіз Клиффпен әңгімеңізді 2019 жылдың 11-12 шілдесінде Санкт-Петербургте өтетін Hydra 2019 конференциясында жалғастыра аласыз. Ол есеппен келеді «Azul аппараттық транзакциялық жады тәжірибесі». Билеттерді сатып алуға болады ресми сайтында.

Ақпарат көзі: www.habr.com

пікір қалдыру