4 million satr Python kodini terishni tekshirish yo'li. 2-qism

Bugun biz Dropbox Python kodining bir necha million satrlari uchun turdagi boshqaruvni qanday tashkil qilgani haqidagi material tarjimasining ikkinchi qismini nashr etmoqdamiz.

4 million satr Python kodini terishni tekshirish yo'li. 2-qism

Birinchi qismni o'qing

Rasmiy turdagi yordam (PEP 484)

Biz 2014-yil Hack Week davomida Dropbox’da mypy bilan birinchi jiddiy tajribalarimizni o‘tkazdik. Hack Week Dropbox tomonidan o‘tkaziladigan bir haftalik tadbirdir. Bu vaqt ichida xodimlar xohlagan narsasi ustida ishlashi mumkin! Dropbox-ning eng mashhur texnologik loyihalari shu kabi tadbirlarda boshlangan. Ushbu tajriba natijasida biz mypy istiqbolli ko'rinadi degan xulosaga keldik, garchi loyiha hali keng foydalanishga tayyor emas.

O'sha paytda Python tipidagi maslahat tizimlarini standartlashtirish g'oyasi havoda edi. Aytganimdek, Python 3.0 dan boshlab funksiyalar uchun turdagi izohlardan foydalanish mumkin edi, lekin bular sintaksis va semantika aniqlanmagan o'zboshimchalik bilan ifodalangan. Dasturni bajarish jarayonida bu izohlar, asosan, e'tibordan chetda qoldi. Hack Week dan keyin biz semantikani standartlashtirish ustida ishlay boshladik. Bu ish paydo bo'lishiga olib keldi PEP 484 (Guido van Rossum, Lukas Langa va men ushbu hujjat ustida hamkorlik qildik).

Bizning motivlarimizni ikki tomondan ko'rish mumkin. Birinchidan, biz butun Python ekotizimi turdagi maslahatlardan foydalanishga umumiy yondashuvni qabul qilishi mumkinligiga umid qildik (Pythonda “turli izohlar” ekvivalenti sifatida ishlatiladigan atama). Bu, mumkin bo'lgan xavflarni hisobga olgan holda, bir-biriga mos kelmaydigan ko'plab yondashuvlarni qo'llashdan ko'ra yaxshiroqdir. Ikkinchidan, biz Python hamjamiyatining ko'plab a'zolari bilan turdagi annotatsiya mexanizmlarini ochiq muhokama qilishni xohladik. Bu istak qisman Python dasturchilarining keng ommasi oldida tilning asosiy g'oyalaridan "murtadlar" kabi ko'rinishni xohlamasligimiz bilan bog'liq edi. Bu dinamik ravishda terilgan til bo'lib, "o'rdak yozish" deb nomlanadi. Jamiyatda, boshida, statik yozish g'oyasiga nisbatan shubhali munosabat paydo bo'lishi mumkin emas edi. Ammo statik yozish majburiy bo'lmasligi aniq bo'lgandan keyin (va odamlar bu haqiqatan ham foydali ekanligini anglab etgach) bu kayfiyat oxir-oqibat yo'qoldi.

Oxir-oqibat qabul qilingan turdagi maslahat sintaksisi o'sha paytda mypy qo'llab-quvvatlagan narsaga juda o'xshash edi. PEP 484 Python 3.5 bilan 2015 yilda chiqarilgan. Python endi dinamik ravishda yoziladigan til emas edi. Men ushbu voqeani Python tarixidagi muhim bosqich deb o'ylashni yaxshi ko'raman.

Migratsiya boshlanishi

2015 yil oxirida Dropbox mypy ustida ishlash uchun uch kishidan iborat jamoa tuzdi. Ular orasida Gvido van Rossum, Greg Prays va Devid Fisher bor edi. Shu paytdan boshlab vaziyat juda tez rivojlana boshladi. Mypy ning o'sishiga birinchi to'siq ishlash edi. Yuqorida aytib o'tganimdek, loyihaning dastlabki kunlarida men mypy ilovasini C ga tarjima qilish haqida o'yladim, ammo bu fikr hozircha ro'yxatdan o'chirildi. Biz tizimni CPython tarjimonidan foydalangan holda ishga tushirib qoldik, bu mypy kabi vositalar uchun etarlicha tez emas. (PyPy loyihasi, JIT kompilyatori bilan muqobil Python ilovasi ham bizga yordam bermadi.)

Yaxshiyamki, bu erda bizga ba'zi algoritmik yaxshilanishlar yordam berdi. Birinchi kuchli "tezlatuvchi" qo'shimcha tekshirishni amalga oshirish edi. Ushbu takomillashtirish g'oyasi oddiy edi: agar modulning barcha bog'liqliklari mypy-ning oldingi ishga tushirilishidan beri o'zgarmagan bo'lsa, biz bog'liqliklar bilan ishlashda oldingi ishga tushirish vaqtida keshlangan ma'lumotlardan foydalanishimiz mumkin. Biz faqat o'zgartirilgan fayllar va ularga bog'liq bo'lgan fayllar turini tekshirishni amalga oshirishimiz kerak edi. Mypy hatto biroz oldinga bordi: agar modulning tashqi interfeysi o'zgarmasa, mypy ushbu modulni import qilgan boshqa modullarni qayta tekshirishga hojat yo'q deb taxmin qildi.

Katta hajmdagi mavjud kodlarni izohlashda qo'shimcha tekshirish bizga ko'p yordam berdi. Gap shundaki, bu jarayon odatda mypy ning ko'plab iterativ ishlanmalarini o'z ichiga oladi, chunki izohlar asta-sekin kodga qo'shiladi va asta-sekin yaxshilanadi. Mypy ning birinchi ishga tushirilishi hali ham juda sekin edi, chunki uni tekshirish uchun juda ko'p bog'liqliklar bor edi. Keyin vaziyatni yaxshilash uchun biz masofaviy keshlash mexanizmini joriy qildik. Agar mypy mahalliy kesh eskirganligini aniqlasa, u markazlashtirilgan ombordan butun kod bazasi uchun joriy kesh suratini yuklab oladi. Keyin ushbu surat yordamida qo'shimcha tekshiruvni amalga oshiradi. Bu bizni mypy samaradorligini oshirish yo'lida yana bir katta qadam tashladi.

Bu Dropbox-da turdagi tekshiruvni tez va tabiiy ravishda qabul qilish davri edi. 2016 yil oxiriga kelib, bizda Python kodining taxminan 420000 XNUMX qatori bor edi. Ko'pgina foydalanuvchilar turni tekshirishga ishtiyoq bilan qarashdi. Borgan sari ko'proq ishlab chiqish guruhlari Dropbox mypy dan foydalanmoqda.

O'shanda hammasi yaxshi ko'rinardi, lekin hali qiladigan ishlarimiz ko'p edi. Biz loyihaning muammoli sohalarini aniqlash va birinchi navbatda qanday muammolarni hal qilish kerakligini tushunish uchun foydalanuvchilarning vaqti-vaqti bilan ichki so'rovlarini o'tkazishni boshladik (bu amaliyot bugungi kunda ham kompaniyada qo'llaniladi). Eng muhimi, ma'lum bo'lishicha, ikkita vazifa edi. Birinchidan, bizga kodning ko'proq turi kerak edi, ikkinchidan, tezroq ishlash uchun mypy kerak edi. Mypy ni tezlashtirish va uni kompaniya loyihalariga tatbiq etish bo'yicha ishimiz hali tugallanmagani aniq edi. Biz bu ikki vazifaning muhimligini to‘liq anglab, ularni hal etishga kirishdik.

Ko'proq mahsuldorlik!

Qo'shimcha tekshiruvlar mypy-ni tezroq qildi, ammo asbob hali ham etarlicha tez emas edi. Ko'pgina qo'shimcha tekshiruvlar taxminan bir daqiqa davom etdi. Buning sababi tsiklik import edi. Bu, ehtimol, Python-da yozilgan katta kod bazalari bilan ishlagan hech kimni ajablantirmaydi. Bizda yuzlab modullar to'plami bor edi, ularning har biri qolganlarini bilvosita import qilgan. Import siklidagi biron bir fayl o'zgartirilgan bo'lsa, mypy ushbu tsikldagi barcha fayllarni va ko'pincha ushbu tsikldan modullarni import qilgan har qanday modullarni qayta ishlashi kerak edi. Bunday tsikllardan biri Dropbox-da juda ko'p muammolarni keltirib chiqaradigan mashhur "bog'liqlik chigalligi" edi. Ushbu tuzilma bir necha yuz modulni o'z ichiga olgan bo'lsa, u to'g'ridan-to'g'ri yoki bilvosita import qilingan bo'lsa-da, ko'plab testlar ishlab chiqarish kodida ham ishlatilgan.

Biz doiraviy bog'liqliklarni "echish" imkoniyatini ko'rib chiqdik, ammo buni amalga oshirish uchun bizda resurslar yo'q edi. Bizga tanish bo'lmagan juda ko'p kod bor edi. Natijada biz muqobil yondashuvni o'ylab topdik. Biz mypy-ni "qaramlik chalkashliklari" mavjud bo'lganda ham tezda ishlashga qaror qildik. Biz bu maqsadga mypy demoni yordamida erishdik. Demon - bu ikkita qiziqarli xususiyatni amalga oshiradigan server jarayoni. Birinchidan, u butun kod bazasi haqidagi ma'lumotlarni xotirada saqlaydi. Bu shuni anglatadiki, har safar mypy-ni ishga tushirganingizda, minglab import qilingan bog'liqliklar bilan bog'liq keshlangan ma'lumotlarni yuklashingiz shart emas. Ikkinchidan, u kichik tarkibiy bo'linmalar darajasida, funktsiyalar va boshqa ob'ektlar o'rtasidagi bog'liqlikni diqqat bilan tahlil qiladi. Masalan, agar funktsiya foo funksiyani chaqiradi bar, keyin qaramlik mavjud foo от bar. Fayl o'zgarganda, demon birinchi navbatda, alohida holda faqat o'zgartirilgan faylni qayta ishlaydi. Keyin u o'sha faylga tashqi ko'rinadigan o'zgarishlarni, masalan, o'zgartirilgan funksiya imzolarini ko'rib chiqadi. Demon import haqida batafsil ma'lumotdan faqat o'zgartirilgan funksiyadan foydalanadigan funksiyalarni ikki marta tekshirish uchun foydalanadi. Odatda, bu yondashuv bilan siz juda kam funksiyalarni tekshirishingiz kerak.

Bularning barchasini amalga oshirish oson emas edi, chunki asl mypy ilovasi bir vaqtning o'zida bitta faylni qayta ishlashga qaratilgan edi. Kodda biror narsa o'zgargan hollarda biz ko'plab chegaraviy vaziyatlarga duch keldik, ularning paydo bo'lishi takroriy tekshirishni talab qildi. Misol uchun, bu sinfga yangi asosiy sinf tayinlanganda sodir bo'ladi. Biz xohlagan narsani qilganimizdan so'ng, biz ko'pgina qo'shimcha tekshiruvlarni bajarish vaqtini bir necha soniyagacha qisqartira oldik. Bu bizga katta g'alabadek tuyuldi.

Bundan ham ko'proq hosildorlik!

Men yuqorida muhokama qilgan masofaviy keshlash bilan birga, mypy demoni dasturchi tez-tez turdagi tekshiruvni ishga tushirganda, oz sonli fayllarga o'zgartirishlar kiritganda yuzaga keladigan muammolarni deyarli butunlay hal qildi. Biroq, eng kam qulay foydalanish sharoitida tizimning ishlashi hali ham optimaldan uzoq edi. Mypy-ni toza ishga tushirish 15 daqiqadan ko'proq vaqt olishi mumkin. Va bu biz xursand bo'lganimizdan ham ko'proq edi. Har hafta vaziyat yomonlashdi, chunki dasturchilar yangi kod yozishni va mavjud kodga izohlar qo'shishni davom ettirdilar. Bizning foydalanuvchilarimiz hali ham ko'proq ishlashga chanqoq edilar, ammo biz ular bilan yarim yo'lda uchrashganimizdan xursand edik.

Biz mypy haqidagi oldingi fikrlardan biriga qaytishga qaror qildik. Ya'ni, Python kodini C kodiga aylantirish uchun. Cython bilan tajriba (Python-da yozilgan kodni C kodiga tarjima qilish imkonini beruvchi tizim) bizga ko'rinadigan tezlikni bermadi, shuning uchun biz o'z kompilyatorimizni yozish g'oyasini jonlantirishga qaror qildik. Mypy kod bazasi (Pythonda yozilgan) barcha kerakli turdagi izohlarni o'z ichiga olganligi sababli, tizimni tezlashtirish uchun ushbu izohlardan foydalanishga harakat qilish maqsadga muvofiq deb o'yladik. Men bu fikrni sinab ko'rish uchun tezda prototip yaratdim. Bu turli mikro-ko'rsatkichlar bo'yicha ishlashning 10 barobardan ko'proq o'sishini ko'rsatdi. Bizning fikrimiz Python modullarini C modullari uchun Cython yordamida kompilyatsiya qilish va turdagi izohlarni ish vaqti turini tekshirishga aylantirish edi (odatda tip izohlari ish vaqtida e'tiborga olinmaydi va faqat tipni tekshirish tizimlari tomonidan qo'llaniladi). Biz aslida mypy ilovasini Python-dan statik terish uchun mo'ljallangan, xuddi Python-ga o'xshab ko'rinadigan (va, asosan, ishlaydi) tilga tarjima qilishni rejalashtirgan edik. (Bunday tillararo migratsiya mypy loyihasining an'anasiga aylangan. Asl mypy ilovasi Aloreda yozilgan, keyin Java va Python tillarining sintaktik gibridlari mavjud edi).

CPython kengaytmasi API-ga e'tibor qaratish loyihani boshqarish imkoniyatlarini yo'qotmaslik uchun kalit edi. Bizga virtual mashina yoki mypy kerak bo'lgan kutubxonalarni amalga oshirish kerak emas edi. Bundan tashqari, biz hali ham Python ekotizimiga va barcha vositalarga (masalan, pytest) kirishimiz mumkin edi. Bu shuni anglatadiki, biz ishlab chiqish jarayonida talqin qilingan Python kodidan foydalanishni davom ettirishimiz mumkin edi, bu bizga kodni kompilyatsiya qilishni kutish o'rniga, kodni o'zgartirish va uni sinab ko'rishning juda tez namunasi bilan ishlashni davom ettirishga imkon berdi. Biz ikkita stulda o'tirib, ajoyib ish qilganga o'xshdik va bu bizga yoqdi.

Biz mypyc deb atagan kompilyator (chunki u mypy dan turlarni tahlil qilish uchun old qism sifatida foydalanadi) juda muvaffaqiyatli loyiha bo'lib chiqdi. Umuman olganda, biz keshlashsiz tez-tez mypy-yugurishlar uchun taxminan 4x tezlikka erishdik. Mypyc loyihasining yadrosini ishlab chiqish uchun Maykl Sallivan, Ivan Levkivskiy, Xyu Xan va mendan iborat kichik jamoa 4 kalendar oyga yaqin vaqtni oldi. Bu ish hajmi mypy-ni qayta yozish uchun kerak bo'lganidan ancha kichik edi, masalan, C++ yoki Go. Va biz loyihani boshqa tilda qayta yozishda qilishimiz kerak bo'lganidan ko'ra kamroq o'zgartirishlar kiritishimiz kerak edi. Shuningdek, biz mypyc-ni boshqa Dropbox dasturchilari o'z kodlarini kompilyatsiya qilish va tezlashtirish uchun ishlatishlari mumkin bo'lgan darajaga olib kelishimizga umid qildik.

Ushbu darajadagi ishlashga erishish uchun biz ba'zi qiziqarli muhandislik echimlarini qo'llashimiz kerak edi. Shunday qilib, kompilyator tez, past darajadagi C konstruksiyalaridan foydalangan holda ko'plab operatsiyalarni tezlashtirishi mumkin, masalan, kompilyatsiya qilingan funktsiya chaqiruvi C funktsiyasi chaqiruviga tarjima qilinadi. Va bunday qo'ng'iroq talqin qilingan funktsiyani chaqirishdan ko'ra tezroq. Lug'atni qidirish kabi ba'zi operatsiyalar hali ham CPython'dan muntazam C-API qo'ng'iroqlarini ishlatish bilan bog'liq bo'lib, ular kompilyatsiya qilinganda biroz tezroq edi. Biz talqin orqali yaratilgan tizimga qo'shimcha yukni bartaraf etishga muvaffaq bo'ldik, ammo bu holda bu ishlash jihatidan ozgina daromad keltirdi.

Eng keng tarqalgan "sekin" operatsiyalarni aniqlash uchun biz kodni profillashni amalga oshirdik. Ushbu ma'lumotlar bilan qurollangan holda, biz mypyc-ni bunday operatsiyalar uchun tezroq C kodini yaratishi uchun o'zgartirishga harakat qildik yoki tezroq operatsiyalar yordamida mos keladigan Python kodini qayta yozishga harakat qildik (va ba'zida bizda bu yoki boshqa muammoni hal qilishning oddiy echimi yo'q edi). . Python kodini qayta yozish ko'pincha kompilyator avtomatik ravishda bir xil transformatsiyani amalga oshirishdan ko'ra muammoni hal qilish uchun osonroq edi. Uzoq muddatda biz ushbu o'zgarishlarning ko'pini avtomatlashtirishni xohladik, lekin o'sha paytda biz minimal harakat bilan mypyni tezlashtirishga e'tibor qaratgan edik. Va bu maqsad sari harakatlanib, biz bir nechta burchaklarni kesib tashladik.

Davomi bor…

Hurmatli o'quvchilar! Uning mavjudligini bilganingizda mypy loyihasi haqida qanday taassurot qoldirdingiz?

4 million satr Python kodini terishni tekshirish yo'li. 2-qism
4 million satr Python kodini terishni tekshirish yo'li. 2-qism

Manba: www.habr.com

a Izoh qo'shish