Å odien publicÄjam otro daļu par materiÄlu par to, kÄ Dropbox organizÄja tipu kontroli daudziem miljoniem Python kodu rindiÅu.
ā
OficiÄlÄ tipu atbalsts (PEP 484)
MÄs veicÄm pirmos nopietnos eksperimentus ar mypy Dropbox laikÄ Hack Week 2014. Hack Week ir pasÄkums, ko Dropbox organizÄ vienas nedÄļas garumÄ. Å ajÄ laikÄ darbinieki var strÄdÄt pie jebkÄ! Daži no slavenÄkajiem tehnoloÄ£iju projektiem Dropbox sÄkÄs tieÅ”i Å”ajos pasÄkumos. Å Ä« eksperimenta rezultÄtÄ mÄs nonÄcÄm pie secinÄjuma, ka mypy izskatÄs solÄ«gi, lai gan Å”is projekts vÄl nebija gatavs plaÅ”ai izmantoÅ”anai.
TajÄ laikÄ gaisÄ virmoja ideja par Python tipu norÄžu sistÄmu standartizÄÅ”anu. KÄ jau teicu, sÄkot no Python 3.0 bija iespÄjams izmantot tipu anotÄcijas funkcijÄm, taÄu tÄs bija tikai nejauÅ”i izteikumi, bez definÄta sintakses un semantikas. Izpildes laikÄ Å”Ä«s anotÄcijas lielÄkoties tika vienkÄrÅ”i ignorÄtas. PÄc Hack Week mÄs sÄkÄm strÄdÄt pie semantikas standartizÄÅ”anas. Å is darbs noveda pie (uz Å”o dokumentu kopÄ«gi strÄdÄja Gvido van Rossum, Luka Lange un es).
MÅ«su motivÄcija varÄja tikt skatÄ«ta no divÄm pusÄm. PirmkÄrt, mÄs cerÄjÄm, ka visa Python ekosistÄma varÄtu pieÅemt kopÄ«gu pieeju tipu norÄžu (type hints - termins, kas tiek izmantots Python kÄ analoÄ£ija ātipu anotÄcijÄmā) izmantoÅ”anai. Tas, Åemot vÄrÄ iespÄjamos riskus, bÅ«tu labÄk nekÄ izmantot daudzus savstarpÄji nesavienojamus pieejas. OtrkÄrt, mÄs vÄlÄjÄmies atklÄti apspriest tipu anotÄcijas mehÄnismus ar daudziem Python kopienes pÄrstÄvjiem. DaļÄji Å”o vÄlmi noteica tas, ka mÄs nevÄlÄjÄmies izskatÄ«ties kÄ ānospiedÄjiā pret pamata valodas idejÄm plaÅ”Ä Python programmÄtÄju acÄ«s. Tas ir dinamiski tipizÄts valoda, kas pazÄ«stama ar āpÄ«les tipizÄcijuā. KopienÄ, sÄkumÄ nevarÄja neizcelties nedaudz aizdomÄ«ga attieksme pret statiskÄs tipizÄcijas ideju. Bet Å”Äds noskaÅojums galu galÄ vÄjÄks - pÄc tam, kad kļuva skaidrs, ka statiskÄ tipizÄcija netiek plÄnota darÄ«t obligÄtu (un pÄc tam, kad cilvÄki saprata, ka tÄ patieÅ”Äm ir noderÄ«ga).
PieÅemtais sintakse veids bija ļoti lÄ«dzÄ«gs tam, ko tajÄ laikÄ atbalstÄ«ja mypy. PEP 484 dokuments tika izlaists kopÄ ar Python 3.5 2015. gadÄ. Python vairs nebija valoda, kas atbalsta tikai dinamisko tipizÄciju. Man patÄ«k domÄt par Å”o notikumu kÄ par nozÄ«mÄ«gu pagrieziena punktu Python vÄsturÄ.
MigrÄcijas sÄkums
2015. gada beigÄs Dropbox tika izveidota trÄ«s cilvÄku komanda darbam pie mypy. TajÄ bija Gvido van Rossum, Gregs Praiss un Deivids FiÅ”ers. No Ŕī brīža situÄcija sÄka strauji attÄ«stÄ«ties. Pirmais ŔķÄrslis mypy izaugsmei bija veiktspÄja. KÄ jau iepriekÅ” minÄju, agrÄ«najÄ projekta attÄ«stÄ«bas posmÄ es domÄju par mypy realizÄcijas pÄrvietoÅ”anu uz C valodu, bet Ŕī ideja tika atcelta. MÄs iestrÄgÄm ar to, ka sistÄmas palaiÅ”anai tika izmantots CPython interpreters, kas nav pietiekami Ätrs tÄdiem rÄ«kiem kÄ mypy. (Projekts PyPy, alternatÄ«va Python realizÄcija ar JIT kompilatoru, arÄ« mums nepalÄ«dzÄja.)
Par laimi, Å”eit mums palÄ«gÄ nÄca daži algoritmiskie uzlabojumi. Pirmais jaudÄ«gais "paÄtrinÄtÄjs" bija inkrementÄlÄs pÄrbaudes realizÄcija. Å Ä« uzlabojuma ideja bija vienkÄrÅ”a: ja kopÅ” iepriekÅ”ÄjÄs mypy palaiÅ”anas visas moduļa atkarÄ«bas nav mainÄ«juÅ”Äs, tad mÄs varam izmantot, strÄdÄjot ar atkarÄ«bÄm, iepriekÅ”ÄjÄ sesijÄ kausÄtus datus. Mums bija nepiecieÅ”ams tikai veikt tipu pÄrbaudi mainÄ«tajos failos un failos, kas no tiem bija atkarÄ«gi. Mypy gÄja pat vÄl tÄlÄk: ja moduļa ÄrÄjÄ saskarne nebija mainÄ«jusies, mypy uzskatÄ«ja, ka citi moduļi, kas importÄ Å”o moduli, nav jÄverificÄ atkÄrtoti.
InkrÄmentÄlÄ pÄrbaude ļoti palÄ«dzÄja mums, anotÄjot lielus esoÅ”Ä koda apjomus. Proti, Å”is process parasti ietver daudzas iteratÄ«vas mypy palaiÅ”anas, jo anotÄcijas pakÄpeniski tiek pievienotas kodam un pakÄpeniski uzlabojas. Pirmais mypy palaiÅ”ana joprojÄm bija ļoti lÄna, jo tÄs izpildes laikÄ bija jÄpÄrbauda daudz atkarÄ«bu. TÄpÄc mÄs, lai uzlabotu situÄciju, Ä«stenojÄm attÄlinÄtÄs keÅ”atmiÅas mehÄnismu. Ja mypy atklÄj, ka lokÄlÄ keÅ”atmiÅa, iespÄjams, ir novecojusi, tas lejupielÄdÄ aktuÄlo keÅ”atmiÅas attÄlu visai kodu bÄzei no centralizÄtÄ repozitorija. PÄc tam tas veic, izmantojot Å”o attÄlu, inkrÄmentÄlo pÄrbaudi. Tas bija vÄl viens bÅ«tisks solis mÅ«su ceÄ¼Ä uz mypy veiktspÄjas palielinÄÅ”anu.
TÄ bija Ätras un dabiski ieviestas tipa pÄrbaudes sistÄmas ievieÅ”anas perioda Dropbox. Mums lÄ«dz 2016. gada beigÄm jau bija aptuveni 420000 rindu Python koda ar tipu anotÄcijÄm. Daudzi lietotÄji ar entuziasmu uzÅÄma tipu pÄrbaudi. Dropbox mypy arvien vairÄk izmantoja dažÄdas izstrÄdÄtÄju komandas.
Toreiz viss izskatÄ«jÄs labi, taÄu mums vÄl bija daudz darÄmÄ. MÄs sÄkÄm veikt periodiskus iekÅ”Äjus lietotÄju aptaujas, lai identificÄtu projekta vÄjÄs vietas un saprastu, kÄdas problÄmas jÄrisina vispirms (Ŕī prakse tiek izmantota uzÅÄmumÄ arÄ« mÅ«sdienÄs). VisdziļÄkais, kÄ izrÄdÄ«jÄs, bija divas uzdevumu grupas. Pirmais ā nepiecieÅ”ams lielÄks koda segums ar tipiem, otrais ā nepiecieÅ”ams, lai mypy darbotos ÄtrÄk. PilnÄ«gi skaidri bija tas, ka mÅ«su darbs pie mypy paÄtrinÄÅ”anas un tÄ ievieÅ”anas uzÅÄmuma projektos vÄl nebija pabeigts. Apzinoties Å”o divu uzdevumu svarÄ«gumu, mÄs Ä·ÄrÄmies pie to risinÄÅ”anas.
VairÄk veiktspÄjas!
InkrimentÄlÄs pÄrbaudes paÄtrinÄja mypy, taÄu Å”is rÄ«ks joprojÄm nebija pietiekami Ätrs. Daudzas inkrimentÄlÄs pÄrbaudes aizÅÄma aptuveni minÅ«ti. Iemesls tam bija cikliskie importi. Tas, iespÄjams, nepÄrsteigs tos, kuri ir strÄdÄjuÅ”i ar lielÄm Python kodu bÄzÄm. Mums bija simtiem moduļu, no kuriem katrs netieÅ”i importÄja visus pÄrÄjos. Ja jebkurÅ” fails cikla importos tika mainÄ«ts, mypy nÄcÄs apstrÄdÄt visus failus, kas bija ietverti Å”ajÄ ciklÄ, un bieži vÄl arÄ« jebkÄdus moduļus, kas importÄja moduļus no Ŕī cikla. Viens no Å”iem cikliem bija slavenais āatkarÄ«bu mezglsā, kas radÄ«ja daudz nepatikÅ”anu Dropbox. Reiz Ŕī struktÅ«ra ietvÄra vairÄkus simtus moduļu, un to importÄja, tieÅ”i vai netieÅ”i, daudzi testi, kÄ arÄ« to izmantoja produkcijas kodÄ.
MÄs apsvÄra iespÄju āatraisÄ«tā cikliskÄs atkarÄ«bas, taÄu mums nebija resursu to izdarÄ«t. Tur bija pÄrÄk daudz koda, ar kuru mÄs nebijÄm pazÄ«stami. Galu galÄ mÄs izvÄlÄjÄmies alternatÄ«vu pieeju. MÄs nolÄmÄm panÄkt, lai mypy darbotos Ätri pat tad, ja ir āatkarÄ«bu mezgliā. MÄs sasniedzÄm Å”o mÄrÄ·i ar mypy dmeonu. Dmeons ir servera process, kas Ä«steno divas interesantas iespÄjas. PirmkÄrt ā tas saglabÄ visus kodu bÄzes datus atmiÅÄ. Tas nozÄ«mÄ, ka katru reizi, palaižot mypy, nav jÄielÄdÄ keÅ”atmiÅÄ esoÅ”ie dati, kas saistÄ«ti ar tÅ«kstoÅ”iem importÄto atkarÄ«bu. OtrkÄrt ā tas rÅ«pÄ«gi analÄ«zÄ attiecÄ«bas starp funkcijÄm un citÄm entÄ«tijÄm sÄ«ku struktÅ«ru lÄ«menÄ«. PiemÄram, ja funkcija foo izsauc funkciju bar, tad ir atkarÄ«ba foo no bar. Kad fails tiek mainÄ«ts, dmeons vispirms atseviŔķi apstrÄdÄ tikai mainÄ«to failu. PÄc tam tas aplÅ«ko Ŕī faila izmaiÅas, kas ir redzamas no Ärpuses, piemÄram, mainÄ«tÄs funkciju paraksti. Dmeons izmanto detalizÄtu informÄciju par importiem tikai, lai pÄrbaudÄ«tu tÄs funkcijas, kuras faktiski izmanto mainÄ«to funkciju. Parasti Å”Ädas pieejas gadÄ«jumÄ jÄpÄrbauda salÄ«dzinoÅ”i maz funkciju.
Visu Å”o Ä«stenoÅ”ana bija sarežģīta, jo sÄkotnÄjÄ mypy realizÄcija bija ļoti vÄrsta uz viena faila apstrÄdi vienlaicÄ«gi. Mums nÄcÄs saskarties ar daudzÄm robežsituÄcijÄm, kuru raÅ”anÄs prasÄ«ja atkÄrtotas pÄrbaudes, kad kodÄ tika veiktas izmaiÅas. PiemÄram, tas notiek, kad klasei tiek pieŔķirta jauna pamatklase. PÄc tam, kad mÄs izdarÄ«jÄm to, ko vÄlÄjÄmies, mÄs spÄjam samazinÄt vairuma inkrementÄlo pÄrbaudes laiku lÄ«dz dažÄm sekundÄm. Mums tas Ŕķita liels sasniegums.
VÄl lielÄka veiktspÄja!
KopÄ ar attÄlinÄto keÅ”atmiÅu, par kuru es iepriekÅ” runÄju, mypy demonstrators praktiski pilnÄ«bÄ atrisinÄja problÄmas, kas radÄs, kad programmÄtÄjs bieži veic tipu pÄrbaudi, veicot izmaiÅas nelielÄ failu skaitÄ. TomÄr sistÄmas veiktspÄja, visneizdevÄ«gÄkajÄ tÄs izmantoÅ”anas scenÄrijÄ, joprojÄm bija tÄlu no optimÄlÄs. TÄ«ra mypy palaiÅ”ana varÄja aizÅemt vairÄk nekÄ 15 minÅ«tes. Un tas bija daudz vairÄk, nekÄ mÅ«s apmierinÄtu. Katru nedÄļu situÄcija kļuva aizvien sliktÄka, jo programmÄtÄji turpinÄja rakstÄ«t jaunu kodu un pievienot anotÄcijas esoÅ”ajam kodam. MÅ«su lietotÄji joprojÄm ilgojÄs pÄc lielÄkas veiktspÄjas, un mÄs ar prieku bijÄm gatavi viÅiem palÄ«dzÄt.
MÄs nolÄmÄm atgriezties pie vienas no agrÄkajÄm idejÄm par mypy. Proti, par Python koda pÄrvÄrÅ”anu C kodÄ. Eksperimenti ar Cython (kas ir sistÄma, kas ļauj tulkot Python rakstÄ«tu kodu C kodÄ) mums deva maz redzamu uzlabojumu, tÄdÄļ mÄs nolÄmÄm atdzÄ«vinÄt ideju par sava kompilatora rakstīŔanu. TÄ kÄ mypy kodu bÄze (rakstÄ«ta Python) jau ietvÄra visas nepiecieÅ”amÄs tipu anotÄcijas, mums likÄs vÄrts mÄÄ£inÄt izmantot Ŕīs anotÄcijas, lai paÄtrinÄtu sistÄmas darbÄ«bu. Es Ätri izveidoju prototipu, lai pÄrbaudÄ«tu Å”o ideju. Tas rÄdÄ«ja vairÄk nekÄ desmitkÄrtÄ«gu veiktspÄjas pieaugumu dažÄdos mikro-benchmarks. MÅ«su ideja bija kompilÄt Python moduļus C moduļos, izmantojot Cython, un pÄrvÄrst tipu anotÄcijas par tipu pÄrbaudÄm, kas tiek veiktas programmas izpildes laikÄ (parasti tipu anotÄcijas programmÄ tiek ignorÄtas izpildes laikÄ un tiek izmantotas tikai tipu pÄrbaudes sistÄmÄs). MÄs faktiski plÄnojÄm pÄrvÄrst mypy realizÄciju no Python uz valodu, kas ir statiski tipizÄta, kas izskatÄ«tos (un lielÄkoties darbotos) tieÅ”i tÄpat kÄ Python. (Å is interlangu Ä£enÄzes variants kļuva par kaut kÄdu tradÄ«ciju mypy projektÄ. SÄkotnÄjÄ mypy realizÄcija tika rakstÄ«ta Alore, pÄc tam bija sintaktisks hibrÄ«ds starp Java un Python).
OrientÄcija uz CPython paplaÅ”inÄjumu API bija atslÄga, lai nezaudÄtu projekta pÄrvaldÄ«bas iespÄjas. Mums nebija jÄrealizÄ virtuÄlÄ maŔīna vai jebkuras bibliotÄkas, kas bija nepiecieÅ”amas mypy. TurklÄt mÄs joprojÄm varÄjÄm piekļūt visai Python ekosistÄmai, visi rÄ«ki (piemÄram, pytest) bÅ«tu pieejami. Tas nozÄ«mÄja, ka mÄs varÄjÄm turpinÄt izmantot interpretÄto Python kodu izstrÄdes laikÄ, kas ļautu mums turpinÄt darbu, izmantojot ļoti Ätru kodu labojumu un testÄÅ”anas shÄmu, nevis gaidÄ«t koda kompilÄciju. IzskatÄ«jÄs, ka mums lieliski izdodas, tÄ sakot, sÄdÄt uz diviem krÄsliem, un mÄs to baudÄ«jÄm.
Kompilators, ko mÄs nosaucÄm par mypyc (jo tas kÄ frontend izmanto mypy tipu analÄ«zei), izrÄdÄ«jÄs samÄrÄ veiksmÄ«gs projekts. KopumÄ mÄs sasniedzÄm aptuveni 4 reizes ÄtrÄkus mypy izsaukumus bez keÅ”oÅ”anas izmantoÅ”anas. Mypyc projekta kodola izstrÄdei nelielai komandai, kurÄ ietilpa Maikls Salivans, Ivans Levkivskis, HjÅ« Hens un es, bija nepiecieÅ”ami apmÄram 4 kalendÄra mÄneÅ”i. Å is darba apjoms bija daudz mazÄks nekÄ tas, kas bÅ«tu vajadzÄ«gs, lai pÄrrakstÄ«tu mypy, piemÄram, uz C++ vai Go. Un arÄ« izmaiÅu skaits, ko mums vajadzÄja ieviest projektÄ, bija krietni mazÄks, nekÄ tas bÅ«tu nepiecieÅ”ams, pÄrrakstot to citÄ valodÄ. MÄs, turklÄt, cerÄjÄm, ka varÄsim mypyc aizvest lÄ«dz tÄdam lÄ«menim, lai to varÄtu izmantot, lai kompilÄtu un paÄtrinÄtu savu kodu, arÄ« citi Dropbox programmÄtÄji.
Lai sasniegtu Å”Ädu veiktspÄju, mums nÄcÄs pielietot dažus interesantus inženiertehniskus risinÄjumus. PiemÄram, kompilators spÄj paÄtrinÄt daudzas operÄcijas, izmantojot ÄtrÄs zemÄ lÄ«meÅa C konstrukcijas. PiemÄram, izsaukums uz kompilÄtu funkciju tiek pÄrvÄrsts par izsaukumu uz C funkciju. Un tÄds izsaukums tiek veikts daudz ÄtrÄk nekÄ interpretÄtÄ funkcija. Dažas operÄcijas, tÄdas kÄ meklÄÅ”ana vÄrdnÄ«cÄs, joprojÄm palika pie parastajiem C-API izsaukumiem no CPython, kas pÄc kompilÄcijas izrÄdÄ«jÄs tikai nedaudz ÄtrÄkas. MÄs spÄjam atbrÄ«voties no papildu slodzes uz sistÄmu, ko radÄ«ja interpretÄcija, taÄu Å”ajÄ gadÄ«jumÄ tas sniedza tikai nelielu peļÅu veiktspÄjÄ.
Lai identificÄtu visizplatÄ«tÄkÄs "lÄnÄs" operÄcijas, mÄs veicÄm koda profilÄÅ”anu. Ar iegÅ«tajiem datiem mÄs centÄmies vai nu uzlabot mypyc, lai tas Ä£enerÄtu ÄtrÄku C kodu Å”ÄdÄm operÄcijÄm, vai pÄrrakstÄ«t atbilstoÅ”o Python kodu, izmantojot ÄtrÄkas operÄcijas (dažreiz mums vienkÄrÅ”i nebija pietiekami vienkÄrÅ”a risinÄjuma Å”ai vai tai problÄmai). Python koda pÄrrakstīŔana bieži izrÄdÄ«jÄs vieglÄks risinÄjums problÄmai nekÄ automÄtiska tÄ paÅ”a transformÄcijas Ä«stenoÅ”ana kompilatorÄ. IlgtermiÅÄ mÄs vÄlÄjÄmies automatizÄt daudzas no Ŕīm transformÄcijÄm, bet tajÄ brÄ«dÄ« mÄs fokusÄjÄmies uz to, lai ar minimÄlu piepÅ«li paÄtrinÄtu mypy. Un, virzoties uz Å”o mÄrÄ·i, mÄs izgriezÄm dažus stÅ«rīŔus.
TurpinÄjums sekosā¦
CienÄ«jamie lasÄ«tÄji! KÄdas bija jÅ«su sajÅ«tas par mypy projektu, kad uzzinÄjÄt par tÄ pastÄvÄÅ”anu?
Avots: habr.com
