Python кодунун 4 миллион саптарын терүүнүн жолу. 2-бөлүк

Бүгүн биз Dropbox Python кодунун бир нече миллион саптары үчүн типти башкарууну кантип уюштурганы тууралуу материалдын котормосунун экинчи бөлүгүн жарыялап жатабыз.

Python кодунун 4 миллион саптарын терүүнүн жолу. 2-бөлүк

Биринчи бөлүгүн оку

Расмий колдоо түрү (PEP 484)

Биз 2014-жылы Hack Week учурунда Dropbox'то mypy менен биринчи олуттуу эксперименттерди өткөрдүк. Hack Week Dropbox тарабынан уюштурулган бир жумалык иш-чара. Бул убакыттын ичинде кызматкерлер каалагандай иштей алышат! Dropbox'тун эң белгилүү технологиялык долбоорлорунун айрымдары ушул сыяктуу иш-чараларда башталган. Бул эксперименттин на-тыйжасында биз долбоор кенири колдонууга даяр эмес болсо да, mypy перспективалуу окшойт деген тыянакка келдик.

Ошол учурда, Python типтеги кыйытма системаларын стандартташтыруу идеясы абада болчу. Мен айткандай, Python 3.0ден бери функциялар үчүн типтеги аннотацияларды колдонсо болот, бирок булар синтаксиси жана семантикасы аныкталбаган, жөн гана эркин туюнтмалар болгон. Программаны аткаруу учурунда, бул аннотациялар, негизинен, жөн гана этибарга алынбай калган. Hack Week кийин, биз семантиканы стандартташтыруу боюнча иштей баштадык. Бул иш пайда болушуна алып келди PEP 484 (Гвидо ван Россум, Лукаш Ланга жана мен бул документте кызматташканбыз).

Биздин ниеттерибизди эки тараптан кароого болот. Биринчиден, биз бүт Python экосистемасы типтеги ишараттарды (Python тилинде "тип аннотацияларына" эквивалент катары колдонулган термин) колдонууга жалпы мамилени кабыл алат деп үмүттөндүк. Бул, мүмкүн болгон тобокелдиктерди эске алганда, бири-бирине туура келбеген көптөгөн ыкмаларды колдонуудан көрө жакшыраак болмок. Экинчиден, биз Python коомчулугунун көптөгөн мүчөлөрү менен типтеги аннотация механизмдерин ачык талкуулагыбыз келди. Бул каалоо жарым-жартылай Python программисттердин кеңири массасынын көз алдында тилдин негизги идеяларынан "чектөөчүлөр" сыяктуу көрүнгүбүз келбегендиги менен шартталган. Бул "өрдөк терүү" деп аталган динамикалык терилген тил. Коомчулукта, эң башында, статикалык терүү идеясына карата бир аз шектүү мамиле пайда боло алган жок. Бирок бул сезим акырында статикалык терүү милдеттүү болбой турганы айкын болгондон кийин (жана адамдар анын чындыгында пайдалуу экенин түшүнгөндөн кийин) басаңдап калды.

Акыры кабыл алынган типтеги кыйытма синтаксиси ошол убакта mypy колдогон нерсеге абдан окшош болчу. PEP 484 Python 3.5 менен 2015-жылы чыгарылган. Python динамикалык терилген тил болбой калды. Мен бул окуяны Python тарыхындагы маанилүү этап деп эсептегим келет.

Миграциянын башталышы

2015-жылдын аягында Dropbox mypy боюнча иштөө үчүн үч адамдан турган команда түзгөн. Алардын арасында Гидо ван Россум, Грег Прайс жана Дэвид Фишер болгон. Ошол учурдан тартып кырдаал абдан тез өнүгүп баштады. mypy-дун есушуне биринчи кедергиси-ти аткаруу болду. Мен жогоруда кыйытып айткандай, долбоордун алгачкы күндөрүндө мен mypy ишке ашырууну C тилине которууну ойлогом, бирок бул идея азырынча тизмеден чыгып кетти. Биз системаны CPython котормочу аркылуу иштете албай калдык, бул mypy сыяктуу куралдар үчүн тез эмес. (PyPy долбоору, JIT компилятору менен альтернативалуу Python ишке ашыруу да бизге жардам берген жок.)

Бактыга жараша, бул жерде кээ бир алгоритмдик жакшыртуулар жардамга келди. Биринчи күчтүү "тездеткич" кошумча текшерүүнү ишке ашыруу болгон. Бул өркүндөтүүнүн идеясы жөнөкөй эле: эгерде бардык модулдун көз карандылыгы mypyдин мурунку иштетилишинен бери өзгөрбөсө, анда биз көз карандылыктар менен иштөөдө мурунку иштетүүдө кэштелген маалыматтарды колдоно алабыз. Бизге жөн гана өзгөртүлгөн файлдарда жана аларга көз каранды болгон файлдарда түрүн текшерүү керек болчу. Mypy дагы бир аз алдыга кетти: эгер модулдун тышкы интерфейси өзгөрбөсө, mypy бул модулду импорттогон башка модулдарды кайра текшерүүнүн кереги жок деп ойлогон.

Учурдагы коддун чоң көлөмүн аннотациялоодо кошумча текшерүү бизге көп жардам берди. Кеп, бул процесс адатта mypyдин көптөгөн итеративдик иштешин камтыйт, анткени аннотациялар кодго акырындык менен кошулуп, акырындык менен жакшыртылып турат. mypy биринчи иштетүү дагы эле өтө жай болду, анткени текшерүү үчүн көп көз каранды болгон. Андан кийин кырдаалды жакшыртуу үчүн биз алыстан кэштөө механизмин ишке киргиздик. Эгерде mypy жергиликтүү кэштин эскирип калганын аныктаса, ал борборлоштурулган репозиторийден бүт код базасы үчүн учурдагы кэштин сүрөтүн жүктөп алат. Андан кийин бул сүрөттү колдонуу менен кошумча текшерүү жүргүзөт. Бул бизди mypy-нун ендурумдуулугун жогорулатууга карай дагы бир зор кадам шилтеди.

Бул Dropbox'та типти текшерүүнү тез жана табигый кабыл алуу мезгили болгон. 2016-жылдын акырына карата бизде типтеги аннотациялары бар Python кодунун болжол менен 420000 XNUMX саптары бар болчу. Көптөгөн колдонуучулар типти текшерүүгө шыктанышкан. Барган сайын көбүрөөк иштеп чыгуучу командалар Dropbox mypyди колдонушту.

Ошондо баары жакшы көрүнгөн, бирок биз дагы жасай турган иштерибиз көп болчу. Долбоордун көйгөйлүү жерлерин аныктоо жана биринчи кезекте кандай маселелерди чечүү керектигин түшүнүү үчүн биз мезгил-мезгили менен ички колдонуучуларды сурамжылоолорду жүргүзө баштадык (бул практика компанияда бүгүнкү күндө дагы колдонулат). Эң негизгиси, белгилүү болгондой, эки милдет болгон. Биринчиден, бизге коддун көбүрөөк түрү керек болчу, экинчиден, тезирээк иштөө үчүн mypy керек болчу. mypy тездетуу жана аны фирмалык долбоорлорго киргизуу боюнча биздин иш али да болсо аягына чыга элек экенди-ги ачык эле тушунуктуу эле. Биз бул эки милдеттин маанилүүлүгүн толук түшүнүп, аларды чечүүгө кириштик.

Көбүрөөк өндүрүмдүүлүк!

Кошумча текшерүүлөр mypyду тездетти, бирок курал дагы эле жетиштүү эмес. Көптөгөн кошумча текшерүүлөр бир мүнөткө созулду. Буга циклдик импорт себеп болгон. Бул Python тилинде жазылган чоң код базалары менен иштегендерди таң калтырбайт. Бизде жүздөгөн модулдар бар болчу, алардын ар бири башкаларын кыйыр түрдө импорттогон. Импорттук циклдеги кандайдыр бир файл өзгөртүлгөн болсо, mypy ал циклдеги бардык файлдарды жана көбүнчө ал циклден модулдарды импорттогон бардык модулдарды иштеп чыгышы керек болчу. Ушундай циклдердин бири Dropboxто көп кыйынчылыктарды жараткан атактуу "көз карандылыктын чыр-чатагы" болгон. Бул түзүм бир нече жүз модулдарды камтыгандан кийин, импорттолгон, түз же кыйыр түрдө көптөгөн тесттер, ал өндүрүш кодексинде да колдонулган.

Биз тегерек көз карандылыктарды «чектөө» мүмкүнчүлүгүн карап чыктык, бирок аны ишке ашырууга каражатыбыз жок болчу. Биз билбеген өтө көп код бар эле. Натыйжада биз альтернативалуу ыкманы ойлоп таптык. Биз «көз карандылыктын түйшүгү» болгон учурда да mypy тез иштөөнү чечтик. Биз бул максатка mypy демону менен жеттик. Демон эки кызыктуу функцияны ишке ашырган сервер процесси. Биринчиден, ал эстутумда бүт код базасы жөнүндө маалыматты сактайт. Бул mypy иштеткен сайын миңдеген импорттолгон көз карандылыктарга байланыштуу кэштелген маалыматтарды жүктөөнүн кереги жок дегенди билдирет. Экинчиден, ал майда түзүмдүк бөлүмдөрдүн деңгээлинде функциялар менен башка субъектилердин ортосундагы көз карандылыкты кылдат талдайт. Мисалы, эгерде функция foo функцияны чакырат bar, анда көз карандылык бар foo от bar. Файл өзгөргөндө, демон биринчиден, обочолонуп, өзгөртүлгөн файлды гана иштетет. Андан кийин ал файлга сырттан көрүнүүчү өзгөртүүлөрдү карайт, мисалы, өзгөргөн функция кол тамгалары. Демон модификацияланган функцияны чындыгында колдонгон функцияларды эки жолу текшерүү үчүн гана импорт жөнүндө толук маалыматты колдонот. Адатта, бул ыкма менен сиз өтө аз функцияларды текшеришиңиз керек.

Мунун бардыгын ишке ашыруу оңой болгон жок, анткени баштапкы mypy ишке ашыруу бир эле учурда бир файлды иштетүүгө багытталган. Бизге көптөгөн чек ара кырдаалдары менен күрөшүүгө туура келди, алардын пайда болушу кодексте бир нерсе өзгөргөн учурларда кайталап текшерүүнү талап кылды. Мисалы, бул класска жаңы базалык класс ыйгарылганда болот. Биз каалаган нерсени жасагандан кийин, биз кошумча текшерүүлөрдүн көбүнүн аткарылуу убактысын бир нече секундага чейин кыскарта алдык. Бул биз үчүн чоң жеңиштей көрүндү.

Андан да көбүрөөк өндүрүмдүүлүк!

Мен жогоруда талкуулаган алыстан кэштөө менен бирге mypy демону программист типти текшерүүнү тез-тез иштетип, аз сандагы файлдарга өзгөртүүлөрдү киргизгенде пайда болгон көйгөйлөрдү дээрлик толугу менен чечти. Бирок, эң аз ыңгайлуу шартта системанын иштеши дагы эле оптималдуу эмес. mypy таза ишке киргизүү 15 мүнөттөн ашык убакыт талап кылынышы мүмкүн. Жана бул биз бактылуу боло тургандан алда канча көп болду. Апта сайын кырдаал начарлап кетти, анткени программисттер жаңы кодду жазууну жана учурдагы кодго аннотацияларды кошууну уланта беришти. Биздин колдонуучулар дагы эле көбүрөөк аткарууну каалашкан, бирок биз аларды жарым жолдо тосуп алганыбызга кубанычта болдук.

mypy боюнча мурдагы идеялардын бирине кайтып барууну чечтик. Тактап айтканда, Python кодун C кодуна айландыруу. Cython менен эксперимент жүргүзүү (Pythonдо жазылган кодду C кодуна которууга мүмкүндүк берген система) бизге эч кандай көзгө көрүнөрлүк ылдамдыкты берген жок, ошондуктан биз өзүбүздүн компиляторубузду жазуу идеясын жандандырууну чечтик. mypy коддук базасы (Python тилинде жазылган) бардык керектүү аннотацияларды камтыгандыктан, биз системаны тездетүү үчүн бул аннотацияларды колдонууга аракет кылууну максатка ылайыктуу деп ойлодук. Мен бул идеяны сынап көрүү үчүн тез прототибин түздүм. Бул ар кандай микро-баяндоо боюнча көрсөткүчтөрдүн 10 эседен ашык өсүшүн көрсөттү. Биздин идея Python модулдарын C модулдарына Cython аркылуу компиляциялоо жана типтеги аннотацияларды аткаруу убакытындагы текшерүүлөргө айландыруу болчу (адатта тип аннотациялары иштөө убагында этибарга алынбайт жана типти текшерүү системалары тарабынан гана колдонулат). Биз чындыгында mypy ишке ашырууну Python тилинен статикалык түрдө терүү үчүн иштелип чыккан тилге которууну пландаштырганбыз, ал так Python сыяктуу көрүнөт (жана, негизинен, иштейт). (Тилдер аралык миграциянын мындай түрү mypy долбоорунун салтына айланган. Баштапкы mypy ишке ашыруу Alore тилинде жазылган, андан кийин Java жана Python тилдеринин синтаксистик гибриди болгон).

CPython кеңейтүү API'сине басым жасоо долбоорду башкаруу мүмкүнчүлүктөрүн жоготпоонун ачкычы болгон. Виртуалдык машинаны же mypy керек болгон китепканаларды ишке ашыруунун кереги жок болчу. Мындан тышкары, биз дагы эле Python экосистемасына жана бардык куралдарга (мисалы, pytest) кире алабыз. Бул иштеп чыгуу учурунда чечмеленген Python кодун колдонууну уланта аларыбызды билдирген, бул бизге коддун компиляциясын күтпөстөн, кодду өзгөртүүнүн жана аны сынап көрүүнүн абдан тез үлгүсү менен иштөөнү улантууга мүмкүндүк берди. Мындайча айтканда, эки отургучка отуруп, абдан жакшы иш кылып жаткандай көрүндүк жана бул бизге абдан жакты.

Биз mypyc деп атаган компилятор (анткени ал mypyди типтерди талдоо үчүн алдыңкы бөлүк катары колдонот) абдан ийгиликтүү долбоор болуп чыкты. Жалпысынан, биз кэшсиз тез-тез mypy иштетүү үчүн болжол менен 4 эсе ылдамдыкка жетиштик. Mypyc проектиниц эсасыны ишлэп дузмек учин Майкл Салливандан, Иван Левкивскиден, Хью Хандан ве менден ыбарат болан кичижик бригада 4 календардык айга жакын убакытты талап кылды. Бул жумуштун көлөмү, мисалы, C++ же Go тилдеринде mypyди кайра жазуу үчүн талап кылынгандан бир топ азыраак болгон. Жана башка тилде кайра жазганда долбоорго бир топ азыраак өзгөртүүлөрдү киргизүүгө туура келди. Ошондой эле биз mypycти башка Dropbox программисттери өз коддорун түзүү жана тездетүү үчүн колдоно тургандай деңгээлге жеткире алабыз деп үмүттөндүк.

Мындай көрсөткүчкө жетүү үчүн биз кызыктуу инженердик чечимдерди колдонууга туура келди. Ошентип, компилятор тез, төмөнкү деңгээлдеги С конструкцияларын колдонуу менен көптөгөн операцияларды тездете алат.Мисалы, компиляцияланган функция чакырыгы С функциясынын чакыруусуна которулат. Жана мындай чакыруу интерпретацияланган функцияны чакырууга караганда алда канча тезирээк. Кээ бир операциялар, мисалы, сөздүк издөө, CPython'дун кадимки C-API чалууларын колдонууну камтыган, алар компиляцияланганда бир аз ылдамыраак болгон. Биз чечмелөө аркылуу түзүлгөн системага кошумча жүктү жок кыла алдык, бирок бул учурда аткаруу жагынан бир аз гана пайда берди.

Эң кеңири таралган "жай" операцияларды аныктоо үчүн биз код профилин түздүк. Бул маалыматтар менен куралданган биз mypycти мындай операциялар үчүн тезирээк C кодун түзө тургандай кылып өзгөртүүгө аракет кылдык же тезирээк операцияларды колдонуу менен тиешелүү Python кодун кайра жазууга аракет кылдык (жана кээде бизде бул же башка көйгөйдү чечүү үчүн жөнөкөй чечим болгон эмес). . Python кодун кайра жазуу, компилятордун ошол эле трансформацияны автоматтык түрдө аткаруусуна караганда көйгөйдү чечүүнүн оңой жолу болгон. Узак мөөнөттүү келечекте биз мындай трансформациялардын көбүн автоматташтырууну кааладык, бирок ошол учурда биз аз күч менен mypyди тездетүүгө багытталганбыз. Ал эми бул максатка карай жылып, биз бир нече бурчтарды кесип.

Уландысы бар…

Урматтуу окурмандар! Анын бар экендигин билгенде mypy долбоору тууралуу кандай таасир калтырдыңыз?

Python кодунун 4 миллион саптарын терүүнүн жолу. 2-бөлүк
Python кодунун 4 миллион саптарын терүүнүн жолу. 2-бөлүк

Source: www.habr.com

Комментарий кошуу