De Wee fir 4 Millioune Linnen Python Code ze tippen. Deel 2

Haut publizéieren mir den zweeten Deel vun der Iwwersetzung vum Material iwwer wéi Dropbox Typkontrolle fir e puer Millioune Linnen Python Code organiséiert huet.

De Wee fir 4 Millioune Linnen Python Code ze tippen. Deel 2

Liesen Deel eent

Offiziell Typ Ënnerstëtzung (PEP 484)

Mir hunn eis éischt sérieux Experimenter mat mypy bei Dropbox während der Hack Week 2014 gemaach. Hack Week ass en Event vun enger Woch gehost vun Dropbox. Während dëser Zäit kënnen d'Mataarbechter un alles schaffen wat se wëllen! E puer vun de bekanntste Technologieprojete vun Dropbox hunn op Eventer wéi dës ugefaang. Als Resultat vun dësem Experiment hu mir ofgeschloss datt mypy villverspriechend ausgesäit, obwuel de Projet nach net prett ass fir verbreet Benotzung.

Zu där Zäit war d'Iddi fir Python-Typ Hiweissystemer ze standardiséieren an der Loft. Wéi gesot, zënter Python 3.0 war et méiglech Typ Annotatiounen fir Funktiounen ze benotzen, awer dëst ware just arbiträr Ausdréck, ouni definéiert Syntax a Semantik. Wärend der Ausféierung vum Programm goufen dës Annotatiounen zum gréissten Deel einfach ignoréiert. No der Hack Week hu mir ugefaang un der Standardiséierung vun der Semantik ze schaffen. Dës Aarbecht huet zum Entstoe gefouert PEP 484 eng (Guido van Rossum, Łukasz Langa an ech hunn un dësem Dokument zesummegeschafft).

Eis Motiver konnte vun zwou Säiten gekuckt ginn. Als éischt hu mir gehofft datt de ganze Python-Ökosystem eng gemeinsam Approche fir d'Benotzung vun Typhintunge kéint adoptéieren (e Begrëff deen am Python als Äquivalent vun "Typ Annotatiounen" benotzt gëtt). Dëst, mat de méigleche Risiken, wier besser wéi vill géigesäiteg inkompatibel Approche ze benotzen. Zweetens, mir wollten offen Typ Annotatiounsmechanismen mat ville Membere vun der Python Gemeinschaft diskutéieren. Dëse Wonsch gouf deelweis diktéiert vun der Tatsaach, datt mir net wéi "Apostate" aus de Grondidee vun der Sprooch an den Ae vun de breede Massen vu Python Programméierer kucken wëllen. Et ass eng dynamesch getippten Sprooch, bekannt als "Enten Tippen". An der Gemeinschaft, am Ufank, eng e bësse verdächteg Haltung vis-à-vis vun der Iddi vum statesche Tippen konnt net hëllefen, awer entstinn. Awer dat Gefill ass schlussendlech ofgeschwächt nodeems et kloer gouf datt statesch Tippen net obligatoresch wier (an nodeems d'Leit gemierkt hunn datt et tatsächlech nëtzlech war).

D'Typ Hiweis Syntax, déi schlussendlech ugeholl gouf, war ganz ähnlech wéi d'Mypy deemools ënnerstëtzt huet. PEP 484 gouf mam Python 3.5 am Joer 2015 verëffentlecht. Python war net méi eng dynamesch getippten Sprooch. Ech denken gär un dëst Evenement als e bedeitende Meilesteen an der Python Geschicht.

Start vun der Migratioun

Enn 2015 huet Dropbox en Team vun dräi Leit erstallt fir un mypy ze schaffen. Dozou gehéieren de Guido van Rossum, de Greg Price an den David Fisher. Vun deem Moment un huet sech d'Situatioun extrem séier entwéckelt. Den éischten Hindernis fir dem Mypy säi Wuesstum war d'Performance. Wéi ech uewen ugedeit hunn, hunn ech an de fréie Deeg vum Projet geduecht d'Mypy Implementatioun op C ze iwwersetzen, awer dës Iddi gouf fir de Moment vun der Lëscht gekräizt. Mir ware festgehalen mam System mat dem CPython Dolmetscher ze lafen, wat net séier genuch ass fir Tools wéi mypy. (De PyPy Projet, eng alternativ Python Implementatioun mat engem JIT Compiler, huet eis och net gehollef.)

Glécklecherweis sinn e puer algorithmesch Verbesserungen eis hei zur Hëllef komm. Den éischte mächtege "Accelerator" war d'Ëmsetzung vun der inkrementeller Kontroll. D'Iddi hannert dëser Verbesserung war einfach: wann all d'Ofhängegkeete vum Modul net geännert hunn zënter dem fréiere Laf vu mypy, da kënne mir d'Daten benotzen, déi während der viregter Laf gespäichert sinn, wärend mir mat Ofhängegkeeten schaffen. Mir brauche just Typprüfung op de modifizéierten Dateien an op de Fichieren ze maachen, déi dovun ofhänken. Mypy ass souguer e bësse méi wäit gaang: wann déi extern Interface vun engem Modul net geännert huet, huet mypy ugeholl datt aner Moduler, déi dëse Modul importéiert hunn, net nach eng Kéier iwwerpréift musse ginn.

Inkrementell Iwwerpréiwung huet eis vill gehollef wann Dir grouss Quantitéiten un existente Code annotéiert. De Punkt ass datt dëse Prozess normalerweis vill iterative Runen vu Mypy involvéiert well Annotatiounen graduell an de Code bäigefüügt ginn a graduell verbessert ginn. Den éischte Laf vu mypy war nach ëmmer ganz lues well et vill Ofhängegkeete fir ze kontrolléieren huet. Dann, fir d'Situatioun ze verbesseren, hu mir e Remote Caching Mechanismus implementéiert. Wann mypy feststellt datt de lokalen Cache méiglecherweis verréckt ass, luet den aktuellen Cache-Snapshot fir déi ganz Codebase aus dem zentraliséierte Repository erof. Et mécht dann eng inkrementell Kontroll mat dësem Snapshot. Dëst huet eis e méi grousse Schrëtt geholl fir d'Performance vu mypy ze erhéijen.

Dëst war eng Period vu schneller an natierlecher Adoptioun vun Typprüfung bei Dropbox. Bis Enn 2016 hu mir schonn ongeféier 420000 Zeilen Python Code mat Typ Annotatiounen. Vill Benotzer ware begeeschtert iwwer Typprüfung. Méi a méi Entwécklungsteams hunn Dropbox mypy benotzt.

Alles huet deemools gutt ausgesinn, mä mir haten nach vill ze maachen. Mir hunn ugefaang periodesch intern Benotzer Ëmfroen auszeféieren fir Problemberäicher vum Projet z'identifizéieren an ze verstoen wat d'Problemer als éischt musse geléist ginn (dës Praxis gëtt haut nach an der Firma benotzt). Déi wichtegst, wéi kloer gouf, waren zwou Aufgaben. Als éischt hu mir méi Typofdeckung vum Code gebraucht, zweetens hu mir Mypy gebraucht fir méi séier ze schaffen. Et war absolut kloer datt eis Aarbecht fir d'Mypy ze beschleunegen an se an Firmeprojeten ëmzesetzen nach wäit net fäerdeg war. Mir, voll bewosst vun der Wichtegkeet vun dësen zwou Aufgaben, hu mir eis op d'Léisung gesat.

Méi Produktivitéit!

Inkrementell Kontrollen hunn mypy méi séier gemaach, awer d'Tool war nach ëmmer net séier genuch. Vill inkrementell Kontrollen hunn ongeféier eng Minutt gedauert. De Grond dofir war zyklesch Importer. Dëst wäert wahrscheinlech keen iwwerraschen, dee mat grousse Codebasen geschafft huet, déi am Python geschriwwe sinn. Mir haten Sätz vun Honnerte vu Moduler, déi all déi aner indirekt importéiert hunn. Wann e Fichier an enger Import Loop geännert gouf, muss mypy all Dateien an där Loop veraarbechten, an dacks all Moduler déi Moduler aus där Loop importéiert hunn. Een esou Zyklus war de berühmten "Ofhängegkeetswénkel" dee vill Probleemer bei Dropbox verursaacht huet. Wann dës Struktur e puer honnert Moduler enthält, wärend se importéiert gouf, direkt oder indirekt, vill Tester, gouf se och am Produktiounscode benotzt.

Mir hunn d'Méiglechkeet ugesinn fir kreesfërmeg Ofhängegkeeten ze "entfalen", awer mir haten net d'Ressourcen fir dat ze maachen. Et war ze vill Code datt mir net vertraut waren. Als Resultat hu mir eng alternativ Approche komm. Mir hu beschloss mypy séier ze maachen, och a Präsenz vu "Ofhängegkeetsstécker". Mir hunn dëst Zil erreecht mam mypy Daemon. En Daemon ass e Serverprozess deen zwee interessant Feature implementéiert. Als éischt späichert et Informatioun iwwer déi ganz Codebase an der Erënnerung. Dëst bedeit datt all Kéier wann Dir mypy leeft, musst Dir keng cachedaten am Zesummenhang mat Dausende vun importéierten Ofhängegkeeten lueden. Zweetens, analyséiert hien suergfälteg, um Niveau vu klenge strukturellen Eenheeten, d'Ofhängegkeeten tëscht Funktiounen an aneren Entitéiten. Zum Beispill, wann d'Funktioun foo rifft eng Funktioun bar, da gëtt et eng Ofhängegkeet foo от bar. Wann eng Datei ännert, veraarbecht den Daemon als éischt, isoléiert, nëmmen déi geännert Datei. Et kuckt dann op extern sichtbar Ännerungen an där Datei, sou wéi geännert Funktiounssignaturen. Den Daemon benotzt detailléiert Informatioun iwwer d'Importer nëmmen fir d'Funktiounen ze iwwerpréiwen déi tatsächlech déi modifizéiert Funktioun benotzen. Typesch, mat dëser Approche musst Dir ganz wéineg Funktiounen iwwerpréiwen.

All dëst ëmsetzen war net einfach, well déi ursprénglech mypy Implementatioun staark konzentréiert war op d'Veraarbechtung vun enger Datei gläichzäiteg. Mir hu mat ville Grenzsituatiounen ze dinn, déi optriede vun deenen widderholl Kontrollen verlaangt hunn, wou eppes am Code geännert huet. Zum Beispill geschitt dat wann eng Klass eng nei Basisklass zougewisen gëtt. Eemol hu mir gemaach wat mir wollten, mir konnten d'Ausféierungszäit vun de meescht inkrementelle Kontrollen op nëmmen e puer Sekonnen reduzéieren. Dëst huet eis wéi eng grouss Victoire geschéngt.

Nach méi Produktivitéit!

Zesumme mam Remote-Caching, deen ech hei uewen diskutéiert hunn, huet de mypy-Daemon bal komplett d'Problemer geléist, déi entstinn wann e Programméierer dacks Typprüfung leeft, Ännerunge fir eng kleng Unzuel u Dateien. Wéi och ëmmer, d'Systemleistung am mannst gënschtege Benotzungsfall war nach wäit vun optimal. E propper Startup vu mypy kéint iwwer 15 Minutten daueren. An dat war vill méi wéi mir frou gewiescht wieren. All Woch ass d'Situatioun verschlechtert wéi d'Programméierer weider neie Code schreiwen an Annotatiounen un existente Code bäidroen. Eis Benotzer waren nach ëmmer hongereg fir méi Leeschtung, awer mir ware frou se hallef ze treffen.

Mir hu beschloss op eng vun de fréieren Iddien iwwer mypy zréckzekommen. Nämlech fir Python Code an C Code ze konvertéieren. Experimentéiere mam Cython (e System deen Iech erlaabt Code geschriwwen am Python an C Code ze iwwersetzen) huet eis keng sichtbar Geschwindegkeet ginn, also hu mir beschloss d'Iddi z'erliewen fir eisen eegene Compiler ze schreiwen. Well d'mypy Codebase (schrëftlech am Python) schonn all déi néideg Typ Annotatiounen enthält, hu mir geduecht datt et derwäert wier dës Annotatiounen ze benotzen fir de System ze beschleunegen. Ech hunn séier e Prototyp erstallt fir dës Iddi ze testen. Et huet eng méi wéi 10-fach Erhéijung vun der Leeschtung op verschiddene Mikro-Benchmarks gewisen. Eis Iddi war Python Moduler op C Moduler ze kompiléieren mat Cython, an Typ Annotatiounen a Runtime Typ Kontrollen ëmzewandelen (normalerweis Typ Annotatiounen ginn an der Runtime ignoréiert a benotzt nëmme vun Typ Kontrollsystemer). Mir hu eigentlech geplangt d'Mypy-Implementatioun vu Python an eng Sprooch ze iwwersetzen, déi entwéckelt gouf fir statesch getippt ze ginn, déi ausgesäit (a fir de gréissten Deel funktionnéiert) genau wéi Python. (Dës Aart vu Cross-Language Migratioun ass eppes vun enger Traditioun vum Mypy-Projet ginn. Déi ursprénglech Mypy-Implementatioun gouf an Alore geschriwwen, duerno gouf et e syntaktesch Hybrid vu Java a Python).

De Fokus op d'CPython Extensioun API war de Schlëssel fir net de Projektmanagementfäegkeeten ze verléieren. Mir brauche keng virtuell Maschinn oder all Bibliothéiken ze implementéieren déi mypy gebraucht huet. Zousätzlech hätte mir nach ëmmer Zougang zum ganze Python-Ökosystem an all Tools (wéi Pytest). Dëst huet gemengt datt mir weider interpretéiert Python Code wärend der Entwécklung benotze kënnen, wat eis erlaabt weider mat engem ganz schnelle Muster ze schaffen fir Code Ännerungen ze maachen an ze testen, anstatt op de Code ze waarden fir ze kompiléieren. Et huet ausgesinn wéi wann mir eng super Aarbecht maache fir op zwee Still ze sëtzen, souzesoen, a mir hunn et gär.

De Compiler, dee mir mypyc genannt hunn (well et mypy als Frontend fir d'Analyse vun Typen benotzt), huet sech als e ganz erfollegräiche Projet erausgestallt. Insgesamt hu mir ongeféier 4x Geschwindegkeet erreecht fir dacks Mypy Lafen ouni Cache. D'Entwécklung vum Kär vum mypyc Projet huet e klengt Team vum Michael Sullivan, Ivan Levkivsky, Hugh Hahn, a mir selwer ongeféier 4 Kalennerméint gedauert. Dëse Betrag vun der Aarbecht war vill méi kleng wéi dat wat gebraucht gi wier fir mypy ëmzeschreiwen, zum Beispill an C ++ oder Go. A mir hu vill manner Ännerunge beim Projet misse maachen, wéi mir bei der neier Schreifweis en an enger anerer Sprooch misse maachen. Mir hunn och gehofft datt mir mypyc op esou e Niveau bréngen kéinten datt aner Dropbox Programméierer et benotze fir hire Code ze kompiléieren an ze beschleunegen.

Fir dësen Niveau vun der Leeschtung z'erreechen, hu mir e puer interessant Ingenieursléisungen ugewannt. Sou kann de Compiler vill Operatiounen beschleunegen andeems se séier, niddereg-Niveau C Konstrukter benotzen. An esou en Uruff ass vill méi séier wéi eng interpretéiert Funktioun ze ruffen. E puer Operatiounen, sou wéi Wierderbuch Lookups, hunn nach ëmmer involvéiert regelméisseg C-API Uriff vu CPython ze benotzen, déi nëmme marginal méi séier waren wann se zesummegestallt goufen. Mir konnten déi zousätzlech Belaaschtung op de System erstallt duerch Interpretatioun eliminéieren, awer dëst huet an dësem Fall nëmmen e klenge Gewënn wat d'Leeschtung ugeet.

Fir déi heefegst "lues" Operatiounen z'identifizéieren, hu mir Codeprofiléierung gemaach. Bewaffnet mat dësen Donnéeën hu mir probéiert entweder mypyc ze tweaken sou datt et méi séier C Code fir sou Operatiounen generéiert, oder de entspriechende Python Code mat méi séier Operatiounen iwwerschreiwe (an heiansdo hu mir einfach keng einfach genuch Léisung fir dësen oder anere Problem) . De Python Code nei schreiwen war dacks eng méi einfach Léisung fir de Problem wéi de Compiler automatesch déiselwecht Transformatioun ze maachen. Laangfristeg wollte mir vill vun dësen Transformatiounen automatiséieren, awer deemools ware mir fokusséiert fir Mypy mat minimalem Effort ze beschleunegen. A bei dësem Zil réckelen mir e puer Ecker.

Fir weidergitt ...

Léif Lieser! Wat waren Är Impressioune vum mypy-Projet wéi Dir vu senger Existenz geléiert hutt?

De Wee fir 4 Millioune Linnen Python Code ze tippen. Deel 2
De Wee fir 4 Millioune Linnen Python Code ze tippen. Deel 2

Source: will.com

Setzt e Commentaire