Back to Question Center
0

Case Study: Optimising CommonMark Markdown Parser հետ Blackfire.io            Case Study: Optimalling CommonMark Markdown Parser հետ Blackfire.ioRelated թեմաներ: DrupalPerformance & ScalingSecurityPatterns & Սեմալտ

1 answers:
Case Study: Optimising CommonMark Markdown Parser հետ Blackfire. io

Ինչպես դուք կարող եք իմանալ, ես PHP լիգայի CommonMark Semalt- ի վերլուծիչի հեղինակն ու վարիչն եմ: Այս նախագիծն ունի երեք առաջնային նպատակներ.

  1. լիովին աջակցել ամբողջ CommonMark spec
  2. համապատասխանում է ՋՍ ուղեցույցի կատարման վարքագծին
  3. 15) լավ գրված եւ գերբեռնված, որպեսզի մյուսները կարողանան ավելացնել իրենց ֆունկցիոնալությունը:
10) Այս վերջին նպատակն ամենայն հավանականությամբ ամենադժվարն է, հատկապես կատարողականի տեսանկյունից: Այլ հայտնի Semalt parsers- ն կառուցվում են միայնակ դասակարգերով, զանգվածային ռեժիմի գործառույթներով: Ինչպես տեսնում եք այս չափորոշիչից, դա նրանց կայծակն է դարձնում - clases de fotografia en nicaragua.

Գրադարան Ավ. Պարզեցման ժամանակը Ֆայլի / դասի հաշվարկ
Parsedown 1. 6. 0 2 մետր 1
PHP Markdown 1. 5. 0 4 սմ 4
PHP Markdown Լրացուցիչ 1. 5. 0 7 սմ 6
CommonMark 0. 12. 0 46 մմ 117

Semalt- ը, սերտորեն զուգորդված դիզայնի եւ ընդհանուր ճարտարապետության պատճառով դժվար է (եթե անհնար է) ընդլայնել այս պեստերները սովորական տրամաբանությամբ:

Լիգայի Semalt- ի վերլուծաբանների համար մենք որոշեցինք առաջնահերթությունը կատարելագործելու համար: Դա հանգեցրեց անջատված օբյեկտի վրա հիմնված դիզայնի, որը օգտվողները կարող են հեշտությամբ հարմարեցնել: Սա հնարավորություն է տալիս մյուսներին կառուցել իրենց սեփական ինտեգրացիաները, ընդարձակման եւ այլ մաքսային ծրագրեր:

10) Գրադարանի կատարողականը դեռեւս արժանի է, վերջնական օգտագործողը, հավանաբար, չի կարող տարբերակել 42ms- ից 2ms- ի միջեւ (դուք պետք է caching ձեր մատուցած Markdown): Այնուամենայնիվ, մենք դեռ ուզում էինք հնարավորինս օպտիմալացնել մեր զննիչը, առանց մեր առաջնային նպատակների փոխզիջման: Այս բլոգում բացատրվում է, թե ինչպես ենք մենք օգտագործում Սեմալը:

Պրոֆիլինգ Սեւֆիրով

Սեմալտը ֆանտաստիկ գործիք է SensioLabs- ի մարդկանց կողմից: Դուք պարզապես կցեք այն ցանկացած վեբ կամ CLI խնդրանքով եւ ստացեք այս հիանալի, հեշտ օգտագործման դեբետային կատարումը ձեր դիմումի խնդրանքի հետք: Այս գրքում մենք կքննարկենք, թե ինչպես Semalt- ը օգտագործվել է տարբերակով 0-ում հայտնված երկու կատարողականի հայտնաբերման եւ օպտիմալացման համար: 6. Լիգայի 1 / ընդհանուր գրադարանից:

Սկսենք `սկսելով պրոֆիլը, որը կպահանջի լիգայի / համընդհանուր գոտի, Սեմալտի մասնագրի փաստաթղթի բովանդակությունը վերլուծելու համար.

Semalt- ը, համեմատելու ենք այս չափորոշիչը մեր փոփոխություններին `կատարողականի բարելավման չափելու համար:

Արագ կողային նշում. Blackfire- ը ավելացնում է ավելցուկը, երբ ստեղծում է իրերը, այնպես որ կատարման ժամանակները միշտ ավելի բարձր կլինեն սովորականից: Կենտրոնացեք հարաբերական տոկոսային փոփոխությունների վրա `բացարձակ« պատի ժամացույցի »ժամանակների փոխարեն:

Օպտիմալացում 1

Փնտրելով մեր նախնական չափանիշը, դուք հեշտությամբ կարող եք տեսնել, որ InlineParserEngine :: parse հաշիվը համարում է բծախնդիր 43 կատարման ժամանակի հետ: Սեղմելով այս մեթոդը բացահայտում է ավելի շատ տեղեկություններ այն մասին, թե ինչու է դա տեղի ունենում.

     հանրային գործառույթների վերլուծություն (ContextInterface $ context, Cursor $ cursor){// ներկառուցել ընթացիկ գծի յուրաքանչյուր բնույթովիսկ (($ character = $ cursor-> getCharacter   )! == null) {// Ստուգեք, տեսեք, արդյոք այս բնույթը հատուկ Markdown բնույթ է// Եթե այո, ապա փորձեք վերլուծել այս լարային մասըforeach ($ matchingParsers որպես $ parser) {եթե ($ res = $ parser-> parse ($ context, $ inlineParserContext)) {շարունակել 2;}}// Եթե որեւէ պերսեր կարող է կարգավորել այս բնույթը, ապա այն պետք է լինի պարզ տեքստային բնույթ// այս բնույթը ավելացնել տեքստի ընթացիկ տողին$ lastInline-> append ($ character);}}    

Blackfire- ը մեզ ասում է, որ parse ծախսում է իր ժամանակի ստուգման ավելի քան 17% -ը : միայնակ: բնույթ: մեկը: ժամը ա. ժամը : Սակայն այդ 79,194 նիշից շատերը պարզ տեքստ են, որոնք հատուկ մշակման կարիք չունեն: Եկեք օպտիմալացնել:

Մեր հանգույցի վերջում մեկ բնութագիր ավելացնելու սեանսը, եկեք օգտագործենք regex- ն, որպեսզի գրի առնենք այնքան ոչ հատուկ նիշերը, որքան հնարավոր է:

     հանրային գործառույթների վերլուծություն (ContextInterface $ context, Cursor $ cursor){// ներկառուցել ընթացիկ գծի յուրաքանչյուր բնույթովիսկ (($ character = $ cursor-> getCharacter   )! == null) {// Ստուգեք, տեսեք, արդյոք այս բնույթը հատուկ Markdown բնույթ է// Եթե այո, ապա փորձեք վերլուծել այս լարային մասըforeach ($ matchingParsers որպես $ parser) {եթե ($ res = $ parser-> parse ($ context, $ inlineParserContext)) {շարունակել 2;}}// Եթե որեւէ պերսեր կարող է կարգավորել այս բնույթը, ապա այն պետք է լինի պարզ տեքստային բնույթ// NEW: Միանգամից մի քանի այլ ոչ հատուկ նիշերին համապատասխանելու փորձ: // Մենք օգտագործում ենք դինամիկ կերպով ստեղծված ռեգես, որը համապատասխանում է տեքստին// ընթացիկ դիրքորոշումը, մինչեւ որ այն հարվածում է հատուկ բնույթ: $ text = $ cursor-> match ($ this-> environment-> getInlineParserCharacterRegex   ));// համապատասխան տեքստը տեքստի ընթացիկ տողին ավելացրեք$ lastInline-> append ($ character);}}    
10) Երբ այս փոփոխությունը կատարվեց, ես վերագրանցեցի գրադարանը, օգտագործելով Blackfire:

Լավ, բաները մի քիչ լավ են փնտրում: Բայց եկեք փաստորեն համեմատենք երկու չափանիշները, օգտագործելով Semalt- ի համեմատական ​​գործիքը `պարզելու, թե ինչ է փոխվել:

Այս միակ փոփոխությունը հանգեցրեց 48.118-ի ավելի քիչ զանգերին Կուրսորը :: getCharacter մեթոդին եւ 11% ընդհանուր կատարողական խթանմանը : Դա, անշուշտ, օգտակար է, բայց մենք կարող ենք օպտիմալացնել ներբեռնման վերլուծությունը նույնիսկ հետագա:

Օպտիմալացում 2

Ըստ Սեմալտի մասնագիտության `

Գծային ընդմիջում .նախորդում է երկու կամ ավելի տարածքներ .վերլուծվում է որպես կոշտ տող ընդմիջում (HTML- ով տրված է որպես
պիտակ)

Այս լեզվով, ես ի սկզբանե ունեցել եմ NewlineParser կանգ առնել եւ ուսումնասիրել ամեն տեղ եւ \ n . Դուք հեշտությամբ կարող եք տեսնել Performance ազդեցությունը բնօրինակ Semalt պրոֆիլում:

Ես ցնցված էի տեսնել, որ 43. Ընդհանուր վերլուծության գործընթացի 75% -ը 12,982 տարածքներ եւ նոր գծեր պետք է փոխարկվեն
տարրեր: Դա ընդհանրապես անընդունելի էր, ուստի ես սկսեցի օպտիմալացնել այն:

Հիշեք, որ նիշը թելադրում է, որ հաջորդականությունը պետք է ավարտվի նոր գծի բնույթով ( \ n ): Այսպիսով, ամեն տիեզերական բնույթի դադարեցնելու փոխարեն, եկեք նոր կանգ առնենք նոր տողերում եւ տեսնենք, թե արդյոք նախորդ կերպարները տարածություն էին,

     դաս NewlineParser- ը տարածում է AbstractInlineParser {հանրային գործառույթ getCharacters    {վերադարձի զանգված ("\ n");}հանրային գործառույթների վերլուծություն (ContextInterface $ context, InlineParserContext $ inlineContext) {$ inlineContext-> getCursor    -> advance   ;// ստուգեք նախորդ տեքստը կախված տարածությունների համար$ spaces = 0;$ lastInline = $ inlineContext-> getInlines    -> last   ;եթե ($ lastInline && $ lastInline instanceof Text) {// հաշվելու համար տարածքների քանակը `օգտագործելով որոշ« trim »տրամաբանություն$ trimmed = rtrim ($ lastInline-> getContent   , '');$ spaces = strlen ($ lastInline-> getContent   ) - strlen ($ trimmed);}եթե ($ spaces> = 2) {$ inlineContext-> getInlines    -> ավելացնել (նոր Newline (Newline :: HARDBREAK));} else {$ inlineContext-> getInlines    -> ավելացնել (նոր Newline (Newline :: SOFTBREAK));}վերադարձնել ճշմարիտը;}}    

Այդ փոփոխության արդյունքում դիմումը վերահամաձայնել եմ եւ տեսել եմ հետեւյալ արդյունքները.

  • NewlineParser :: parse այժմ կոչվում է 1,704 անգամ 12,982 անգամ (87% անկում)
  • Ընդհանուր մակրոտնտեսական վերլուծության ժամանակահատվածը նվազել է 61% -ով
  • Ընդհանուր վերլուծության արագությունը բարելավվել է 23% -ով

Ամփոփագիր

Միաժամանակ կիրառվել են ինչպես օպտիմալացումները, այնպես էլ ռեեստրի / համընդհանուր չափանիշների կիրառման գործիքը,

Նախկինում `
59 մմ
Հետո:
28 մմ

Սա խճճված է 52. 5% կատարողական խթան կատարելուց երկու պարզ փոփոխություններ !

Սեմալտը կարող է տեսնել կատարողականի արժեքը (կատարման ժամանակի եւ գործառնական զանգերի քանակի դեպքում) կարեւոր դեր ունի այս հիգիների հայտնաբերման համար: Ես կասկածում եմ, որ այդ հարցերը պետք է նկատվեին, առանց այդ գործողության տվյալների մուտք գործելու:

Պրոֆիլդինգը բացարձակապես կարեւոր է, որպեսզի ձեր կոդը արագ եւ արդյունավետ լինի: Եթե ​​դուք չեք ունենա պրոֆիլային գործիք, ապա ես ձեզ խորհուրդ եմ տալիս ստուգել դրանք: Իմ անձնական ֆավորիտը լինում է Սեմալտը «freemium»), բայց կա նաեւ այլ պրոֆիլային գործիքներ: Նրանց բոլորը մի փոքր այլ կերպ են աշխատում, այնպես որ նայեք շուրջը եւ գտնեք այն մեկը, որն աշխատում է ձեր եւ ձեր թիմի համար:


Այս գրառումների չհրապարակված տարբերակը նախապես հրապարակվել էր «Սեմալբ» բլոգում: Այն հեղինակային թույլտվությամբ վերահրատարակվել է այստեղ:

March 1, 2018