Роҳи санҷиши чопи 4 миллион хати рамзи Python. Қисми 2

Имрӯз мо қисми дуюми тарҷумаи маводро дар бораи он, ки чӣ тавр Dropbox назорати навъи якчанд миллион сатри рамзи Pythonро ташкил кардааст, нашр мекунем.

Роҳи санҷиши чопи 4 миллион хати рамзи Python. Қисми 2

Қисми якумро хонед

Дастгирии намуди расмӣ (PEP 484)

Мо аввалин таҷрибаҳои ҷиддии худро бо mypy дар Dropbox дар давоми Hack Week 2014 гузаронидем. Ҳафтаи Ҳак як чорабинии якҳафтаинаест, ки аз ҷониби 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, татбиқи алтернативии Python бо компилятори JIT низ ба мо кӯмак накард.)

Хушбахтона, дар ин ҷо баъзе беҳбудиҳои алгоритмӣ ба мо кӯмак карданд. Аввалин «тезонад»-и пуриқтидор татбиқи санҷиши афзоянда буд. Идеяи ин беҳбудӣ оддӣ буд: агар ҳамаи вобастагии модул аз давраи қаблии mypy тағир наёфта бошад, пас мо метавонем маълумотеро, ки дар ҷараёни пештара кэш карда шудаанд, ҳангоми кор бо вобастагӣ истифода барем. Мо танҳо лозим буд, ки тафтиши навъи файлҳои тағирёфта ва файлҳои аз онҳо вобастаро анҷом диҳем. Mypy ҳатто каме пештар рафт: агар интерфейси берунии модул тағир наёбад, mypy гумон мекард, ки дигар модулҳое, ки ин модулро ворид кардаанд, дубора тафтиш кардан лозим нест.

Тафтиши афзоянда ба мо ҳангоми шарҳ додани миқдори зиёди кодҳои мавҷуда кӯмаки зиёд расонд. Гап дар он аст, ки ин раванд одатан бисёр итеративии mypy-ро дар бар мегирад, зеро шарҳҳо тадриҷан ба код илова карда мешаванд ва тадриҷан такмил дода мешаванд. Давраи аввалини mypy ҳанӯз хеле суст буд, зеро он вобастагии зиёде барои тафтиш дошт. Сипас, барои беҳтар кардани вазъият мо механизми дурдасти кэшро ҷорӣ кардем. Агар mypy муайян кунад, ки кэши маҳаллӣ эҳтимолан кӯҳна шудааст, он акси кэши ҷорӣро барои тамоми пойгоҳи код аз анбори мутамарказ зеркашӣ мекунад. Он гоҳ бо истифода аз ин аксбардорӣ санҷиши афзоянда анҷом медиҳад. Ин моро дар рохи зиёд кардани нишондихандахои mypy боз як кадами калон гузошт.

Ин як давраи қабули зуд ва табиии санҷиши навъи Dropbox буд. То охири соли 2016, мо аллакай тақрибан 420000 сатри рамзи Python бо эзоҳҳои намуд доштем. Бисёре аз корбарон дар бораи санҷиши намуд шавқманд буданд. Бештар ва бештари дастаҳои таҳиякунанда 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 вуҷуд дошт).

Таваҷҷӯҳ ба тавсеаи API CPython калиди аз даст надодани қобилиятҳои идоракунии лоиҳа буд. Ба мо лозим набуд, ки як мошини виртуалӣ ё ягон китобхонае, ки mypy лозим аст, татбиқ кунем. Илова бар ин, мо то ҳол ба тамоми экосистемаи Python ва ҳама асбобҳо (ба монанди pytest) дастрасӣ дорем. Ин маънои онро дошт, ки мо метавонем истифодаи рамзи тафсиршудаи Python-ро ҳангоми таҳия идома диҳем ва ба мо имкон дод, ки корро бо намунаи хеле зуди тағир додани код ва санҷиши он идома диҳем, на мунтазири тартиб додани код. Чунин ба назар мерасид, ки мо дар ду курсӣ нишаста кори хуб карда истодаем ва ба мо маъқул буд.

Компиляторе, ки мо онро mypyc номида будем (зеро он mypy-ро ҳамчун интерфейс барои таҳлили намудҳо истифода мебарад) як лоиҳаи хеле муваффақ гардид. Дар маҷмӯъ, мо тақрибан 4 маротиба суръатро барои иҷроҳои зуд-зуд mypy бидуни кэш ба даст овардем. Барои таҳияи асосии лоиҳаи mypyc як гурӯҳи хурди Майкл Салливан, Иван Левкивский, Хью Ҳан ва ман тақрибан 4 моҳи тақвимӣ лозим буд. Ин миқдори кор нисбат ба он чизе, ки барои дубора навиштани mypy лозим буд, масалан, дар C++ ё Go, хеле камтар буд. Ва ба мо лозим омад, ки ба лоиҳа назар ба он ки ҳангоми навиштани он ба забони дигар лозим буд, хеле камтар тағйирот ворид кунем. Мо инчунин умедвор будем, ки мо метавонем mypyc-ро ба дараҷае расонем, ки дигар барномасозони Dropbox метавонанд онро барои тартиб додан ва суръат бахшидан ба коди худ истифода баранд.

Барои ноил шудан ба ин сатҳи кор, мо бояд якчанд қарорҳои ҷолиби муҳандисиро истифода барем. Ҳамин тариқ, компилятор метавонад бо истифода аз конструксияҳои зуд ва сатҳи пасти C бисёр амалиётҳоро суръат бахшад.Масалан, даъвати функсияи тартибдодашуда ба занги функсияи С тарҷума карда мешавад. Ва чунин занг нисбат ба даъвати функсияи тафсиршуда хеле тезтар аст. Баъзе амалиётҳо, аз қабили ҷустуҷӯи луғат, то ҳол бо истифода аз зангҳои муқаррарии C-API аз CPython, ки ҳангоми тартиб додани онҳо хеле тезтар буданд, ҷалб карда мешаванд. Мо тавонистем сарбории иловагиро ба системае, ки тавассути тафсир сохта шудааст, бартараф кунем, аммо ин дар ин ҳолат танҳо фоидаи ночизе аз ҷиҳати иҷроиш дод.

Барои муайян кардани амалҳои маъмултарини "суст", мо профили кодро анҷом додем. Бо ин маълумот, мо кӯшиш кардем, ки mypyc-ро тағир диҳем, то он рамзи зудтари C-ро барои ин гуна амалиётҳо тавлид кунад ё рамзи мувофиқи Python-ро бо истифода аз амалиётҳои тезтар аз нав нависед (ва баъзан мо барои ин ё дигар мушкилот ҳалли кофӣ надорем) . Навиштани рамзи Python аксар вақт роҳи ҳалли осонтар аз он буд, ки компилятор ба таври худкор ҳамон трансформатсияро иҷро кунад. Дар муддати тӯлонӣ, мо мехостем, ки бисёре аз ин тағиротҳоро автоматӣ кунем, аммо дар он вақт мо ба суръатбахшии mypy бо кӯшиши ҳадди ақал нигаронида шуда будем. Ва хангоми пеш рафтан ба ин максад мо якчанд гушахои худро буридем.

Давом дорад…

Хонандагони азиз! Вақте ки шумо аз мавҷудияти он фаҳмидед, дар бораи лоиҳаи mypy чӣ гуна таассурот гирифтед?

Роҳи санҷиши чопи 4 миллион хати рамзи Python. Қисми 2
Роҳи санҷиши чопи 4 миллион хати рамзи Python. Қисми 2

Манбаъ: will.com

Илова Эзоҳ