Jalur pikeun typechecking 4 juta garis kode Python. Bagian 2

Dinten ieu kami nyebarkeun bagian kadua tarjamahan bahan ngeunaan kumaha Dropbox ngatur tipe kontrol pikeun sababaraha juta garis kode Python.

Jalur pikeun typechecking 4 juta garis kode Python. Bagian 2

Baca bagian hiji

Pangrojong tipe resmi (PEP 484)

Urang ngalaksanakeun percobaan serius munggaran urang jeung mypy di Dropbox salila Hack Minggu 2014. Hack Minggu nyaéta hiji-minggu acara hosted ku Dropbox. Salila ieu, karyawan tiasa damel naon waé anu dipikahoyong! Sababaraha proyék téknologi Dropbox anu paling kasohor dimimitian dina acara sapertos kieu. Salaku hasil tina percobaan ieu, urang menyimpulkan yén mypy Sigana ngajangjikeun, sanajan proyék nu teu acan siap pikeun pamakéan nyebar.

Dina waktos éta, ideu pikeun ngabakukeun sistem hinting jinis Python aya dina hawa. Salaku Cenah mah, saprak Python 3.0 éta mungkin ngagunakeun tipe annotations pikeun fungsi, tapi ieu ngan éksprési sawenang, tanpa sintaksis diartikeun jeung semantik. Salila palaksanaan program, annotations ieu, pikeun sabagéan ageung, saukur dipaliré. Saatos Hack Minggu, urang mimitian dipake dina standarisasi semantik. Karya ieu ngakibatkeun mecenghulna PEP 484 (Guido van Rossum, Łukasz Langa jeung kuring gawé bareng dina dokumén ieu).

Motif urang tiasa ditingali tina dua sisi. Kahiji, urang miharep yén sakabéh ékosistem Python bisa ngadopsi pendekatan umum pikeun ngagunakeun tipe petunjuk (istilah dipaké dina Python salaku sarua "jenis annotations"). Ieu, tinangtu résiko anu mungkin, bakal langkung saé tibatan ngagunakeun seueur pendekatan anu teu cocog. Kadua, urang hoyong sacara terbuka ngabahas mékanisme anotasi jinis sareng seueur anggota komunitas Python. Kahayang ieu sabagean didikte ku kanyataan yén urang moal hayang kasampak kawas "murtad" tina gagasan dasar basa dina panon massa lega programer Python. Ieu mangrupikeun basa anu diketik sacara dinamis, anu katelah "ketik bebek". Di masarakat, dina awalna, sikep anu rada curiga kana ide ngetik statik teu tiasa ngabantosan. Tapi sentimen éta pamustunganana waned sanggeus éta janten jelas yén ketikan statik teu bade jadi wajib (jeung sanggeus jalma sadar yén éta sabenerna mangpaat).

Sintaksis tipe hint anu antukna diadopsi sami sareng anu dirojong ku mypy dina waktos éta. PEP 484 dileupaskeun nganggo Python 3.5 di 2015. Python henteu deui janten basa anu diketik sacara dinamis. Kuring resep nganggap acara ieu salaku milestone signifikan dina sajarah Python.

Mimitian migrasi

Dina ahir 2015, Dropbox nyiptakeun tim tilu urang pikeun ngerjakeun mypy. Aranjeunna kalebet Guido van Rossum, Greg Price sareng David Fisher. Ti moment éta, kaayaan mimiti ngembangkeun pisan gancang. Halangan munggaran pikeun kamekaran mypy nyaéta kinerja. Salaku I hinted luhur, dina poé mimiti proyék kuring mikir ngeunaan narjamahkeun palaksanaan mypy kana C, tapi gagasan ieu meuntas kaluar daptar pikeun ayeuna. Kami nyangkut sareng ngajalankeun sistem nganggo juru CPython, anu henteu cekap gancang pikeun alat sapertos mypy. (Proyék PyPy, palaksanaan Python alternatif sareng kompiler JIT, ogé henteu ngabantosan kami.)

Untungna, sababaraha perbaikan algoritma parantos ngabantosan kami di dieu. Kahiji kuat "akselerator" éta palaksanaan mariksa Incremental. Gagasan di tukangeun perbaikan ieu basajan: upami sadaya katergantungan modul teu acan robih ti saprak ngajalankeun mypy sateuacana, maka urang tiasa nganggo data anu di-cache salami ngajalankeun sateuacana nalika damel sareng katergantungan. Urang ngan ukur kedah ngalakukeun mariksa jinis dina file anu dirobih sareng file anu gumantung kana éta. Mypy malah indit saeutik salajengna: lamun panganteur éksternal modul a teu robah, mypy nganggap yén modul lianna nu diimpor modul ieu teu perlu dipariksa deui.

Pamariksaan Incremental parantos ngabantosan kami nalika ngémutan sajumlah ageung kode anu aya. Intina nyaéta yén prosés ieu biasana ngalibatkeun seueur panyebaran mypy salaku annotations laun-laun ditambah kana kode sareng laun-laun ningkat. Ngajalankeun mimiti mypy masih lambat pisan sabab ngagaduhan seueur katergantungan pikeun dipariksa. Teras, pikeun ningkatkeun kaayaan, kami ngalaksanakeun mékanisme cache jauh. Upami mypy ngadeteksi yén cache lokal sigana tos lami, éta ngaunduh snapshot cache ayeuna pikeun sakabéh codebase tina gudang terpusat. Éta teras ngalakukeun pamariksaan incremental nganggo snapshot ieu. Ieu parantos nyandak kami hiji léngkah anu langkung ageung pikeun ningkatkeun kinerja mypy.

Ieu mangrupikeun période nyokot pamariksaan jinis anu gancang sareng alami di Dropbox. Nepi ka tungtun taun 2016, urang geus boga kira 420000 garis kode Python jeung tipe annotations. Seueur pangguna anu sumanget ngeunaan mariksa jinis. Langkung seueur tim pamekaran anu nganggo Dropbox mypy.

Sadayana katingali saé, tapi urang masih seueur anu kedah dilakukeun. Kami mimiti ngalaksanakeun survey pangguna internal périodik pikeun ngaidentipikasi daérah masalah proyék sareng ngartos masalah naon anu kedah direngsekeun heula (prakték ieu masih dianggo di perusahaan ayeuna). Anu paling penting, sakumaha anu jelas, nyaéta dua tugas. Mimiti, urang peryogi langkung seueur jinis sinyalna kodeu, kadua, urang peryogi mypy pikeun damel langkung gancang. Jelas pisan yén padamelan urang pikeun nyepetkeun mypy sareng ngalaksanakeunana kana proyék perusahaan masih jauh tina lengkep. Urang, pinuh sadar pentingna dua pancén ieu, nyetél ngeunaan ngarengsekeun aranjeunna.

Langkung produktivitas!

Cék Incremental ngajantenkeun mypy langkung gancang, tapi alatna masih henteu cekap gancang. Loba cék incremental lumangsung ngeunaan hiji menit. Alesan pikeun ieu impor cyclical. Ieu sigana moal kaget saha waé anu parantos damel sareng basis kode ageung anu ditulis dina Python. Kami ngagaduhan sakumpulan ratusan modul, masing-masing sacara henteu langsung ngimpor sadaya anu sanés. Upami aya file dina loop impor anu dirobih, mypy kedah ngolah sadaya file dina loop éta, sareng sering waé modul anu ngimpor modul tina loop éta. Salah sahiji siklus sapertos kitu nyaéta "ketergantungan tangle" anu kasohor anu nyababkeun seueur masalah di Dropbox. Sakali struktur ieu ngandung sababaraha ratus modul, bari eta ieu diimpor, langsung atawa henteu langsung, loba tés, éta ogé dipaké dina kode produksi.

Urang dianggap kamungkinan "untangling" kagumantungan sirkular, tapi urang teu boga daya pikeun ngalakukeunana. Aya teuing kode anu urang teu wawuh. Hasilna, urang datang nepi ka hiji pendekatan alternatif. Kami mutuskeun pikeun ngajantenkeun mypy gancang sanajan dina ayana "ketergantungan kusut". Kami ngahontal tujuan ieu nganggo daemon mypy. Daemon mangrupikeun prosés server anu ngalaksanakeun dua fitur anu pikaresepeun. Firstly, eta nyimpen informasi ngeunaan sakabéh codebase dina mémori. Ieu ngandung harti yén unggal waktos anjeun ngajalankeun mypy, anjeun teu kedah ngamuat data sindangan anu aya hubunganana sareng rébuan dependensi anu diimpor. Bréh, anjeunna taliti, dina tingkat unit struktural leutik, nganalisis kagumantungan antara fungsi jeung éntitas séjén. Contona, upami fungsi foo nelepon hiji fungsi bar, teras aya gumantungna foo от bar. Lamun file robah, daemon kahiji, dina isolasi, prosés ngan file robah. Éta teras ningali parobahan anu katingali sacara éksternal kana file éta, sapertos tanda tangan fungsi anu dirobih. Daemon ngagunakeun inpormasi lengkep ngeunaan impor ngan pikeun mariksa dua kali pungsi anu leres-leres nganggo fungsi anu dirobih. Biasana, kalayan pendekatan ieu, anjeun kedah mariksa sababaraha fungsi.

Nerapkeun sakabéh ieu teu gampang, saprak palaksanaan mypy aslina ieu beurat fokus kana ngolah hiji file dina hiji waktu. Urang kedah nganyahokeun seueur kaayaan wates, anu lumangsungna peryogi cek diulang dina kasus dimana aya anu robih dina kodeu. Salaku conto, ieu kajadian nalika kelas ditugaskeun kelas dasar anyar. Sakali kami ngalakukeun naon anu urang pikahoyong, kami tiasa ngirangan waktos palaksanaan kalolobaan pamariksaan incremental ngan ukur sababaraha detik. Ieu seemed kawas meunangna badag pikeun urang.

Malah leuwih produktivitas!

Kalayan cache jauh anu kuring bahas di luhur, daemon mypy ampir lengkep ngarengsekeun masalah anu timbul nalika programmer sering ngajalankeun pamariksaan jinis, ngarobih sajumlah file. Tapi, kinerja sistem dina kasus pamakéan sahenteuna nguntungkeun masih jauh ti optimal. A ngamimitian bersih tina mypy bisa nyandak leuwih 15 menit. Sareng ieu langkung seueur tibatan anu urang bakal senang. Unggal minggu kaayaan jadi parah sabab programer terus nulis kode anyar jeung nambahkeun annotations kana kode aya. Pamaké kami masih lapar pikeun pagelaran anu langkung seueur, tapi kami bagja pendak sareng aranjeunna satengahna.

Kami mutuskeun pikeun uih deui ka salah sahiji ideu baheula ngeunaan mypy. Nyaéta, pikeun ngarobih kode Python kana kode C. Ékspérimén sareng Cython (sistem anu ngamungkinkeun anjeun narjamahkeun kode anu ditulis dina Python kana kode C) henteu masihan kagancangan anu katingali, ku kituna kami mutuskeun pikeun nyegerkeun ideu nyerat kompiler urang sorangan. Kusabab codebase mypy (ditulis dina Python) parantos ngandung sadaya jinis annotations anu diperyogikeun, kami panginten kedah nyobian nganggo annotations ieu pikeun nyepetkeun sistem. Kuring gancang nyieun prototipe pikeun nguji gagasan ieu. Éta nunjukkeun paningkatan langkung ti 10 kali ganda dina pagelaran dina sababaraha patokan mikro. Gagasan kami nyaéta pikeun nyusun modul Python kana modul C nganggo Cython, sareng ngahurungkeun anotasi jinis kana cék tipe run-time (biasana annotations ngetik teu dipaliré nalika run-time sareng ngan ukur dianggo ku sistem cek tipe). Urang sabenerna rencanana narjamahkeun palaksanaan mypy ti Python kana basa anu dirancang pikeun statically diketik, éta bakal kasampak (jeung, keur bagian paling, dianggo) persis kawas Python. (Jenis migrasi cross-basa ieu geus jadi tradisi tina proyék mypy. Palaksanaan mypy aslina ieu ditulis dina Alore, lajeng aya hibrid sintaksis Java jeung Python).

Fokus kana API extension CPython mangrupikeun konci pikeun henteu kaleungitan kamampuan manajemén proyék. Kami henteu kedah nerapkeun mesin virtual atanapi perpustakaan anu diperyogikeun mypy. Sajaba ti éta, urang masih bakal boga aksés ka sakabéh ékosistem Python jeung sagala parabot (sapertos pytest). Ieu ngandung harti yén urang bisa neruskeun migunakeun kode Python diinterpretasi salila ngembangkeun, sahingga urang neruskeun gawé kalawan pola pisan gancang nyieun parobahan kode sarta nguji éta, tinimbang ngantosan kode pikeun compile. Sigana mah urang ngalakonan pakasaban hébat linggih dina dua korsi, jadi mun nyarita, sarta kami dipikacinta eta.

The compiler, nu urang disebut mypyc (saprak ngagunakeun mypy salaku hareup-tungtung pikeun analisa jenis), tétéla hiji proyék pisan suksés. Gemblengna, urang ngahontal kirang langkung 4x speedup pikeun sering mypy ngalir tanpa cache. Ngembangkeun inti proyék mypyc nyandak tim leutik Michael Sullivan, Ivan Levkivsky, Hugh Hahn, sareng kuring sorangan ngeunaan 4 bulan kalénder. Jumlah karya ieu leuwih leutik batan naon anu diperlukeun pikeun nulis balik mypy, contona, dina C ++ atanapi Go. Sareng urang kedah ngadamel parobihan anu langkung sakedik kana proyék tibatan anu kedah urang laksanakeun nalika nyerat deui dina basa sanés. Kami ogé ngaharepkeun yén kami tiasa nyandak mypyc ka tingkat sapertos anu tiasa dianggo ku programer Dropbox anu sanés pikeun nyusun sareng nyepetkeun kodena.

Pikeun ngahontal tingkat kinerja ieu, urang kedah nerapkeun sababaraha solusi rékayasa anu pikaresepeun. Ku kituna, kompiler nu bisa nyepetkeun loba operasi ku ngagunakeun gancang, constructs low-tingkat C. Contona, panggero fungsi disusun ditarjamahkeun kana panggero fungsi C. Sareng sauran sapertos kitu langkung gancang tibatan nelepon fungsi anu diinterpretasi. Sababaraha operasi, sapertos milarian kamus, masih aub nganggo telepon C-API biasa ti CPython, anu ngan ukur langkung gancang nalika disusun. Kami tiasa ngaleungitkeun beban tambahan dina sistem anu diciptakeun ku interpretasi, tapi dina hal ieu ngan ukur kauntungan anu leutik dina hal kinerja.

Pikeun ngaidentipikasi operasi "laun" anu paling umum, kami ngalaksanakeun profiling kode. Bersenjata sareng data ieu, urang nyobian boh tweak mypyc supados ngahasilkeun kode C anu langkung gancang pikeun operasi sapertos kitu, atanapi nyerat ulang kode Python anu saluyu nganggo operasi anu langkung gancang (sarta kadang urang henteu ngagaduhan solusi anu saderhana pikeun éta atanapi masalah anu sanés) . Nulis ulang kode Python éta mindeng hiji solusi gampang pikeun masalah ti ngabogaan compiler nu otomatis ngalakukeun transformasi sarua. Dina jangka panjang, urang hayang ngajadikeun otomatis loba transformasi ieu, tapi dina waktu éta kami fokus kana nyepetkeun mypy kalawan usaha minimal. Sarta dina pindah ka tujuan ieu, urang motong sababaraha sudut.

Ngalajengkeun…

Pamiarsa Hadirin! Naon kesan anjeun ngeunaan proyék mypy nalika anjeun terang ayana?

Jalur pikeun typechecking 4 juta garis kode Python. Bagian 2
Jalur pikeun typechecking 4 juta garis kode Python. Bagian 2

sumber: www.habr.com

Tambahkeun komentar