It paad nei typechecking 4 miljoen rigels fan Python-koade. Diel 2

Hjoed publisearje wy it twadde diel fan 'e oersetting fan materiaal oer hoe't Dropbox typekontrôle organisearre foar ferskate miljoen rigels Python-koade.

It paad nei typechecking 4 miljoen rigels fan Python-koade. Diel 2

Lês diel ien

Offisjele type stipe (PEP 484)

Wy hawwe ús earste serieuze eksperiminten útfierd mei mypy by Dropbox tidens Hack Week 2014. Hack Week is in ien wike evenemint hosted troch Dropbox. Yn dizze tiid kinne meiwurkers wurkje oan wat se wolle! Guon fan Dropbox's meast ferneamde technologyprojekten begûnen by eveneminten lykas dizze. As gefolch fan dit eksperimint konkludearren wy dat mypy kânsryk liket, hoewol it projekt noch net klear is foar wiidferspraat gebrûk.

Op dat stuit wie it idee fan it standerdisearjen fan Python-type hintingsystemen yn 'e loft. Lykas ik sei, sûnt Python 3.0 wie it mooglik om type annotaasjes te brûken foar funksjes, mar dit wiene gewoan willekeurige útdrukkingen, sûnder definieare syntaksis en semantyk. By it útfieren fan it programma waarden dizze annotaasjes foar it grutste part gewoan negearre. Nei Hack Week begûnen wy te wurkjen oan standerdisearring fan semantyk. Dit wurk late ta it ûntstean PEP 484 (Guido van Rossum, Łukasz Langa en ik wurken gear oan dit dokumint).

Us motiven koene fan twa kanten besjoen wurde. Earst hopen wy dat it hiele Python-ekosysteem in mienskiplike oanpak koe oannimme foar it brûken fan type-hints (in term brûkt yn Python as it ekwivalint fan "type-annotaasjes"). Dit soe, sjoen de mooglike risiko's, better wêze dan it brûken fan in protte ûnderling ynkompatibele oanpak. Twad, wy woenen iepenlik beprate type annotaasje meganismen mei in protte leden fan de Python mienskip. Dizze winsk waard foar in part diktearre troch it feit dat wy net wolle sjen as "apostaten" fan 'e basisideeën fan' e taal yn 'e eagen fan' e brede massa's fan Python-programmeurs. It is in dynamysk typte taal, bekend as "eendtypen". Yn 'e mienskip, oan it begjin, koe in wat fertochte hâlding foar it idee fan statysk typen net oars as ûntstean. Mar dat gefoel ferdwûn úteinlik nei't dúdlik waard dat statysk typen net ferplicht wurde soe (en nei't minsken realisearre dat it eins nuttich wie).

De type hint syntaksis dy't úteinlik waard oannaam wie tige ferlykber mei wat mypy op dat stuit stipe. PEP 484 waard útbrocht mei Python 3.5 yn 2015. Python wie net langer in dynamysk typte taal. Ik tink graach oan dit barren as in wichtige mylpeal yn Python-skiednis.

Begjin fan migraasje

Oan 'e ein fan 2015 makke Dropbox in team fan trije minsken om te wurkjen oan mypy. Under harren wiene Guido van Rossum, Greg Price en David Fisher. Fan dat momint ôf begûn de situaasje ekstreem fluch te ûntwikkeljen. It earste obstakel foar de groei fan mypy wie prestaasjes. Lykas ik hjirboppe oanjoech, tocht ik yn 'e iere dagen fan it projekt oer it oersetten fan' e mypy-ymplemintaasje yn C, mar dit idee waard foarearst fan 'e list oerstutsen. Wy sieten fêst mei it útfieren fan it systeem mei de CPython-tolk, dy't net fluch genôch is foar ark lykas mypy. (It PyPy-projekt, in alternative Python-ymplemintaasje mei in JIT-kompiler, holp ús ek net.)

Gelokkich binne guon algoritmyske ferbetteringen hjir te helpen. De earste krêftige "accelerator" wie de ymplemintaasje fan inkrementele kontrôle. It idee efter dizze ferbettering wie ienfâldich: as alle ôfhinklikens fan 'e module net feroare binne sûnt de foarige run fan mypy, dan kinne wy ​​​​de gegevens brûke dy't yn' e foarige run binne yn 'e cache by it wurkjen mei ôfhinklikens. Wy hoege allinich typekontrôle út te fieren op 'e wizige bestannen en op' e bestannen dy't derfan ôfhingje. Mypy gie sels noch wat fierder: as de eksterne ynterface fan in module net feroaret, gie mypy derfan út dat oare modules dy't dizze module ymportearren net wer kontrolearre hoege te wurden.

Inkrementele kontrôle hat ús in protte holpen by it annotearjen fan grutte hoemannichten besteande koade. It punt is dat dit proses meastentiids in protte iterative runs fan mypy omfettet, om't annotaasjes stadichoan wurde tafoege oan 'e koade en stadichoan ferbettere. De earste run fan mypy wie noch heul stadich, om't it in protte ôfhinklikens hie om te kontrolearjen. Dan, om de situaasje te ferbetterjen, hawwe wy in meganisme foar caching op ôfstân ymplementearre. As mypy ûntdekt dat de lokale cache wierskynlik ferâldere is, downloadt it de hjoeddeistige cache-snapshot foar de folsleine koadebasis fan it sintralisearre repository. It fiert dan in inkrementele kontrôle út mei dizze momintopname. Dit hat ús noch ien grutte stap nommen om de prestaasjes fan mypy te ferheegjen.

Dit wie in perioade fan rappe en natuerlike oanname fan typekontrôle by Dropbox. Oan 'e ein fan 2016 hiene wy ​​al sawat 420000 rigels Python-koade mei typeannotaasjes. In protte brûkers wiene entûsjast oer typekontrôle. Hieltyd mear ûntwikkelingsteams brûkten Dropbox mypy.

Alles seach der doe goed út, mar we hiene noch in soad te dwaan. Wy begûnen periodike ynterne brûkersûndersiken út te fieren om probleemgebieten fan it projekt te identifisearjen en te begripen hokker problemen earst moatte wurde oplost (dizze praktyk wurdt hjoeddedei noch brûkt yn it bedriuw). De wichtichste, sa waard dúdlik, wiene twa taken. Earst hiene wy ​​mear type dekking fan 'e koade nedich, twadde hienen wy mypy nedich om rapper te wurkjen. It wie absolút dúdlik dat ús wurk om mypy te fersnellen en it te ymplementearjen yn bedriuwsprojekten noch lang net folslein wie. Wy, folslein bewust fan it belang fan dizze twa taken, binne oan 'e gong om se op te lossen.

Mear produktiviteit!

Inkrementele kontrôles makken mypy flugger, mar it ark wie noch net fluch genôch. In protte ynkrementele kontrôles duorre sawat in minút. De reden dêrfoar wie sylyske ymporten. Dit sil wierskynlik gjinien ferrasse dy't wurke hat mei grutte koadebases skreaun yn Python. Wy hiene sets fan hûnderten modules, elk fan dy yndirekt ymportearre alle oaren. As in bestân yn in ymportlus feroare waard, moast mypy alle bestannen yn dy lus ferwurkje, en faaks alle modules dy't modules ymporteare út dy loop. Ien sa'n syklus wie de beruchte "ôfhanneling tangle" dy't in protte problemen feroarsake by Dropbox. Sadree't dizze struktuer befette ferskate hûndert modules, wylst it waard ymportearre, direkt of yndirekt, in protte testen, it waard ek brûkt yn produksje koade.

Wy hawwe de mooglikheid beskôge om sirkulêre ôfhinklikens te "ûntwikkeljen", mar wy hiene net de middels om it te dwaan. D'r wie tefolle koade dy't wy net bekend wiene. Dêrtroch kamen wy mei in alternative oanpak. Wy besletten om mypy fluch te wurkjen, sels yn 'e oanwêzigens fan "ôfhinklike tangles". Wy hawwe dit doel berikt mei de mypy-daemon. In daemon is in serverproses dat twa nijsgjirrige funksjes ymplementearret. As earste bewarret it ynformaasje oer de heule koadebase yn it ûnthâld. Dit betsjut dat elke kear as jo mypy útfiere, jo gjin cachegegevens hoege te laden relatearre oan tûzenen ymporteare ôfhinklikens. Twad, hy analysearret soarchfâldich, op it nivo fan lytse strukturele ienheden, de ôfhinklikens tusken funksjes en oare entiteiten. Bygelyks, as de funksje foo ropt in funksje bar, dan is der in ôfhinklikens foo от bar. As in bestân feroaret, ferwurket de daemon earst, yn isolaasje, allinich it feroare bestân. It sjocht dan nei ekstern sichtbere feroarings oan dat bestân, lykas feroare funksje-hantekeningen. De daemon brûkt detaillearre ynformaasje oer ymporten allinich om de funksjes te kontrolearjen dy't de wizige funksje eins brûke. Typysk moatte jo mei dizze oanpak heul pear funksjes kontrolearje.

It útfieren fan dit alles wie net maklik, om't de oarspronklike mypy-ymplemintaasje swier rjochte wie op it ferwurkjen fan ien bestân tagelyk. Wy hiene te krijen mei in protte grinssituaasjes, wêrfan it foarkommen fan werhelle kontrôles fereaske yn gefallen dêr't wat feroare yn 'e koade. Dit bart bygelyks as in klasse in nije basisklasse wurdt tawiisd. As wy ienris dien hawwe wat wy woenen, koene wy ​​de útfieringstiid fan de measte inkrementele kontrôles ferminderje nei mar in pear sekonden. Dit like ús in grutte oerwinning.

Noch mear produktiviteit!

Tegearre mei it caching op ôfstân dy't ik hjirboppe besprutsen, hat de mypy-daemon de problemen hast folslein oplost dy't ûntsteane as in programmeur faaks typekontrôle útfiert, en feroaret in lyts oantal bestannen. Systeemprestaasjes yn it minst geunstige gebrûksgefal wiene lykwols noch fier fan optimaal. In skjinne opstart fan mypy kin mear dan 15 minuten duorje. En dit wie folle mear as dêr't wy bliid mei west hawwe. Elke wike waard de situaasje slimmer as programmeurs trochgean mei it skriuwen fan nije koade en tafoegje annotaasjes oan besteande koade. Us brûkers wiene noch hongerich foar mear prestaasjes, mar wy wiene bliid om se healwei te moetsjen.

Wy besletten om werom te gean nei ien fan 'e eardere ideeën oangeande mypy. Nammentlik om Python-koade te konvertearjen yn C-koade. Eksperimintearjen mei Cython (in systeem wêrmei jo koade skreaun yn Python kinne oersette yn C-koade) joech ús gjin sichtbere fersnelling, dus besleaten wy it idee fan it skriuwen fan ús eigen kompilator opnij te meitsjen. Om't de mypy-koadebase (skreaun yn Python) al alle nedige typeannotaasjes befette, tochten wy dat it de muoite wurdich wêze soe om te besykjen dizze annotaasjes te brûken om it systeem te fersnellen. Ik makke gau in prototype om dit idee te testen. It toande in mear dan 10-fâldige ferheging fan prestaasjes op ferskate mikro-benchmarks. Us idee wie om Python-modules te kompilearjen nei C-modules mei Cython, en type-annotaasjes te feroarjen yn run-time-typekontrôles (meastentiids wurde type-annotaasjes negearre yn 'e runtime en wurde allinich brûkt troch typekontrôlesystemen). Wy wiene eins fan plan om de mypy-ymplemintaasje fan Python oer te setten yn in taal dy't ûntworpen wie om statysk te typen, dy't krekt as Python soe lykje (en, foar it grutste part, wurkje). (Dit soarte fan cross-language migraasje is wurden wat fan in tradysje fan it mypy projekt. De oarspronklike mypy ymplemintaasje waard skreaun yn Alore, doe wie der in syntaktyske hybride fan Java en Python).

Fokus op 'e CPython-útwreiding API wie de kaai foar it net ferliezen fan projektbehearmooglikheden. Wy hoegden gjin firtuele masine te ymplementearjen of alle biblioteken dy't mypy nedich wie. Derneist soene wy ​​noch tagong hawwe ta it hiele Python-ekosysteem en alle ark (lykas pytest). Dit betsjutte dat wy kinne trochgean mei it brûken fan ynterpretearre Python-koade tidens ûntwikkeling, wêrtroch't wy trochgean kinne wurkje mei in heul rap patroan fan koadeferoarings en testen it, ynstee fan wachtsjen op 'e koade om te kompilearjen. It like derop dat wy in geweldige baan diene om op twa stuollen te sitten, om sa te sizzen, en wy fûnen it leuk.

De kompilator, dy't wy mypyc neamden (om't it mypy brûkt as front-end foar it analysearjen fan typen), blykte in heul suksesfol projekt te wêzen. Oer it algemien hawwe wy sawat 4x fersnelling berikt foar faak mypy-runs sûnder caching. It ûntwikkeljen fan 'e kearn fan it mypyc-projekt naam in lyts team fan Michael Sullivan, Ivan Levkivsky, Hugh Hahn, en mysels sawat 4 kalindermoannen. Dit bedrach fan wurk wie folle lytser as wat soe west hawwe nedich om te herskriuwen mypy, bygelyks, yn C ++ of Go. En wy moasten folle minder wizigings oan it projekt oanbringe as by it oerskriuwen fan it projekt yn in oare taal. Wy hoopten ek dat wy mypyc op sa'n nivo koene bringe dat oare Dropbox-programmeurs it koenen brûke om har koade te kompilearjen en te fersnellen.

Om dit nivo fan prestaasjes te berikken, moasten wy wat nijsgjirrige technyske oplossingen tapasse. Sa kin de gearstaller in protte operaasjes fersnelle troch it brûken fan flugge, leech-nivo C-konstruksjes. Bygelyks, in kompilearre funksje-oanrop wurdt oerset yn in C-funksje-oanrop. En sa'n oprop is folle flugger as it neamen fan in ynterpretearre funksje. Guon operaasjes, lykas opsykjen fan wurdboeken, wiene noch altyd belutsen by it brûken fan reguliere C-API-oproppen fan CPython, dy't mar mar mar in bytsje rapper wiene by it kompilearjen. Wy koenen elimineren de ekstra lading op it systeem makke troch ynterpretaasje, mar dit yn dit gefal joech mar in lytse winst yn termen fan prestaasjes.

Om de meast foarkommende "stadige" operaasjes te identifisearjen, hawwe wy koadeprofilearring útfierd. Bewapene mei dizze gegevens besochten wy mypyc oan te passen sadat it rapper C-koade soe generearje foar sokke operaasjes, of de korrespondearjende Python-koade opnij skriuwe mei flugger operaasjes (en soms hienen wy gewoan net in ienfâldige genôch oplossing foar dat of oare probleem) . It oerskriuwen fan de Python-koade wie faaks in maklikere oplossing foar it probleem dan dat de kompilator automatysk deselde transformaasje útfiere. Op lange termyn woenen wy in protte fan dizze transformaasjes automatisearje, mar op it stuit wiene wy ​​rjochte op it fersnellen fan mypy mei minimale ynspanning. En by it ferpleatsen nei dit doel, snije wy ferskate hoeken.

Oanhâlde wurde ...

Dear readers! Wat wiene jo yndrukken fan it mypy-projekt doe't jo learden fan it bestean?

It paad nei typechecking 4 miljoen rigels fan Python-koade. Diel 2
It paad nei typechecking 4 miljoen rigels fan Python-koade. Diel 2

Boarne: www.habr.com

Add a comment