)! == null) {// بررسی کنید تا ببینید آیا این شخصیت یک شخصیت معروف خاص است// اگر چنین است، اجازه دهید آن را امتحان کنید این بخشی از رشته را تجزیه کنیدforeach ($ matchingParsers به عنوان تجزیه کننده $) {اگر $ res = $ parser-> تجزیه ($ context، $ inlineParserContext)) {ادامه 2؛}}// اگر پارس نتواند این شخصیت را اداره کند، باید آن را یک شخصیت متنی ساده داشته باشد// این کاراکتر را به خط فعلی متن اضافه کنید$ lastInline-> add ($ character)؛}} Blackfire به ما می گوید که parse
بیش از 17٪ از زمان چک کردن خود را صرف هر. تنها. شخصیت. یکی در a زمان . اما بیشتر این 79،194 کاراکتر متن ساده هستند که نیازی به دستکاری خاص ندارند! بیایید این را بهینه کنیم
با اضافه کردن یک کاراکتر تک در انتهای حلقه ما، با استفاده از یک regex برای گرفتن بسیاری از کاراکترهای غیر خاص به عنوان ما می توانیم:
تجزیه و تحلیل تابع عمومی (ContextInterface $ context، Cursor $ cursor){// از طریق هر کاراکتر در خط فعلی وارد شویددر حالی که (($ person = $ cursor-> getCharacter )! == null) {// بررسی کنید تا ببینید آیا این شخصیت یک شخصیت معروف خاص است// اگر چنین است، اجازه دهید آن را امتحان کنید این بخشی از رشته را تجزیه کنیدforeach ($ matchingParsers به عنوان تجزیه کننده $) {اگر $ res = $ parser-> تجزیه ($ context، $ inlineParserContext)) {ادامه 2؛}}// اگر پارس نتواند این شخصیت را اداره کند، باید آن را یک شخصیت متنی ساده داشته باشد// NEW: تلاش برای مطابقت با چند کاراکتر غیر خاص در یک بار. // ما از یک regex ایجاد شده به صورت پویا استفاده می کنیم که از متن متناسب است// موقعیت فعلی تا زمانی که به کاراکتر خاصی برسد. $ text = $ cursor-> match ($ this-> environment-> getInlineParserCharacterRegex )؛// متن متناسب را به خط فعلی متن اضافه کنید$ lastInline-> add ($ character)؛}}
وقتی این تغییر ایجاد شد، کتابخانه با استفاده از Blackfire دوباره بازنویسی شد:
خوب، همه چیز کمی بهتر است. اما بگذارید در واقع دو معیار را با استفاده از ابزار مقایسه Semalt مقایسه کنیم تا یک تصویر واضح تر از آنچه که تغییر کرد، مقایسه کنیم:
این تغییر تک منجر به 48،118 تماس کمتر به آن روش Cursor :: getCharacter
و 11٪ افزایش کلی عملکرد ! این قطعا مفید است، اما ما می توانیم تجزیه درون خطی را حتی بیشتر بهینه کنیم.
بهینه سازی 2
با توجه به مشخصات Semalt:
شکست خط .که توسط دو یا چند فضایی پیش می آید .به عنوان یک شکست خط سخت (که در HTML به عنوان یک برچسب
ارائه می شود، تجزیه می شود)
به دلیل این زبان، من در اصل NewlineParser
را متوقف کردم و هر فضای را بررسی و \ n
شخصیت که مواجه شد. شما به راحتی می توانید تاثیر عملکرد را در مشخصات اصلی Semalt ببینید:
43. 75٪ از فرآیند تجزیه ENTIRE بدانید که آیا 12،982 فاصله و خطوط جدید باید به
عناصر. این کاملا غیرقابل قبول بود، بنابراین من تصمیم گرفتم این را بهینه سازی کنم.
به یاد داشته باشید که تنظیمات نشان می دهد که دنباله باید با یک کاراکتر خط جدید ( \ n
) پایان یابد. بنابراین، به جای متوقف کردن در هر شخصیت فضایی، اجازه دهید فقط در خطوط جدید متوقف شود و ببینیم که آیا شخصیت های قبلی فضایی بودند:
کلاس NewlineParser گسترش AbstractInlineParser {تابع عمومی getCharacters {آرایه بازگشتی ("\ n")؛}تجزیه تابع عمومی (ContextInterface $ context، InlineParserContext $ inlineContext) {$ inlineContext-> getCursor -> advance ؛// متن قبلی را برای فضاهای انتهایی بررسی کنید$ spaces = 0؛$ lastInline = $ inlineContext-> getInlines -> last ؛اگر ($ lastInline && lastinline instanceof متن) {// تعداد فضاهای با استفاده از برخی از منطق ترمیم را محاسبه کنید$ trimmed = rtrim ($ lastInline-> getContent ، '')؛$ spaces = strlen ($ lastInline-> getContent ) - strlen ($ trimmed)؛}اگر ($ spaces> = 2) {$ inlineContext-> getInlines -> add (Newline Newline (Newline :: HARDBREAK))؛} else {$ inlineContext-> getInlines -> add (Newline Newline (Newline :: SOFTBREAK))؛}بازگشت درست}}
با این تغییر در محل، برنامه را بازنویسی کردم و نتایج زیر را دیدم:
-
NewlineParser :: parse
در حال حاضر فقط 1،704 بار به جای 12،982 بار (کاهش 87٪) - زمان تجزیه عمومی در زمان واقعی کاهش یافت 61٪
- سرعت کلی تجزیه 23٪ بهبود یافته
خلاصه
هنگامی که هر دو بهینه سازی اجرا شد، من ابزار معیار لیگ / عددی را برای تعیین اثرات عملکرد واقعی در دنیای مجازی اجرا کردم:
- قبل از:
- 59ms
- پس از:
- 28ms
این یک عظیم 52. 5٪ افزایش عملکرد از ساخت دو تغییر ساده !
Semalt قادر به دیدن هزینه های عملکرد (در هر زمان اجرای و تعداد تماس های عملکردی) برای شناسایی این گره های عملکرد حیاتی بود. من بدون شک این مسائل را بدون دسترسی به این داده های عملکرد متوجه شده ام.
پروفایل ها برای اطمینان از اینکه کد شما سریع و کارآمد می باشد بسیار ضروری است. اگر قبلا ابزار پروفایل نداشته اید، من به شدت توصیه می کنم آنها را بررسی کنید. دوست من شخصی به نظر می رسد که سمالت "freemium" است)، اما ابزارهای پروفایل دیگری وجود دارد که وجود دارد. همه آنها کمی متفاوت عمل می کنند، بنابراین اطراف نگاه کنید و یکی از آن ها را که برای شما و تیم شما مناسب است، پیدا کنید.
یک نسخه غیر منتظره از این پست در ابتدا در وبلاگ Semalt منتشر شد. با مجوز نویسنده مجددا منتشر شد.
دیدار با نویسنده
کالین اودل
کولین او دله توسعه دهنده وب سایت در Unleashed Technologies، یک شرکت اینترنتی و میزبانی در مریلند است. او شروع به برنامه ریزی در سن 8 سالگی کرد، وب سایت محلی را در 15 سالگی تاسیس کرد و بیش از 10 سال تجربه حرفه ای با پی اچ پی داشته است. علاوه بر داشتن عضو فعال لیگ PHP و نگهدارنده پروژه لیگ / Commonmark، کولین نیز یک توسعه دهنده Symfony Certified (Expert) و Magento Certified Developer است.