ຕາມທີ່ທ່ານອາດຈະຮູ້, ຂ້າພະເຈົ້າເປັນຜູ້ຂຽນແລະຜູ້ຮັກສາຂອງ PHP Common League Mark Semalt. ໂຄງການນີ້ມີສາມເປົ້າຫມາຍຕົ້ນຕໍ:
- ສະຫນັບສະຫນູນຢ່າງເຕັມສ່ວນຂໍ້ມູນທົ່ວໄປ CommonMark
- ສອດຄ່ອງກັບພຶດຕິກໍາຂອງການປະຕິບັດການອ້າງອີງ JS
- ຈະຖືກຂຽນດີແລະສາມາດຂະຫຍາຍໄດ້ເພື່ອໃຫ້ຄົນອື່ນສາມາດເພີ່ມການເຮັດວຽກຂອງຕົນເອງໄດ້.
ເປົ້າຫມາຍສຸດທ້າຍນີ້ແມ່ນບາງທີອາດເປັນສິ່ງທ້າທາຍຫຼາຍທີ່ສຸດ, ໂດຍສະເພາະແມ່ນຈາກທັດສະນະປະຕິບັດງານ. ຜູ້ວິເຄາະ Semalt ທີ່ມີຊື່ສຽງອື່ນໆທີ່ຖືກສ້າງຂຶ້ນໂດຍໃຊ້ຫ້ອງຮຽນດຽວທີ່ມີຫນ້າທີ່ regex ຫຼາຍ. ດັ່ງທີ່ທ່ານສາມາດເຫັນໄດ້ຈາກມາດຕະຖານນີ້, ມັນເຮັດໃຫ້ພວກເຂົາຟ້າຜ່າໄວ:
ຫ້ອງສະຫມຸດ | Avg Parse Time | File / Class Count |
Parsedown 1 6 0 | 2 ms | 1 |
PHP Markdown 1 5 0 | 4 ms | 4 |
PHP Markdown Extra 1 5 0 | 7 ms | 6 |
CommonMark 0 12 0 | 46 ms | 117 |
Semalt, ເນື່ອງຈາກວ່າການອອກແບບທີ່ແຫນ້ນຫນາແລະສະຖານະພາບລວມ, ມັນຍາກ (ຖ້າບໍ່ແມ່ນສິ່ງທີ່ບໍ່ເປັນໄປໄດ້) ເພື່ອຂະຫຍາຍນັກວິເຄາະເຫຼົ່ານີ້ດ້ວຍເຫດຜົນທີ່ກໍາຫນົດເອງ.
ສໍາລັບນັກວິເຄາະເສດຖະກິດຂອງລີກ, ພວກເຮົາໄດ້ເລືອກທີ່ຈະໃຫ້ຄວາມສໍາຄັນຕໍ່ການປະຕິບັດຫນ້າທີ່. ນີ້ໄດ້ເຮັດໃຫ້ການອອກແບບທີ່ມີຈຸດປະສົງທີ່ແຕກຕ່າງກັນທີ່ຜູ້ໃຊ້ສາມາດປັບແຕ່ງໄດ້ງ່າຍ. ນີ້ໄດ້ເປີດໃຫ້ຜູ້ອື່ນສ້າງການເຊື່ອມໂຍງ, ການຂະຫຍາຍແລະໂຄງການລູກຄ້າອື່ນໆ.
ການປະຕິບັດງານຂອງຫ້ອງສະຫມຸດຍັງຄົງດີ - ຜູ້ໃຊ້ສຸດທ້າຍອາດຈະບໍ່ສາມາດແຍກຄວາມແຕກຕ່າງລະຫວ່າງ 42 ມແລະ 2 ມມ (ທ່ານຄວນຈະຖືກເກັບມ້ຽນ Markdown ຂອງທ່ານແລ້ວ). ຢ່າງໃດກໍຕາມ, ພວກເຮົາຍັງຕ້ອງການທີ່ຈະປັບປຸງໃຫ້ດີທີ່ສຸດເທົ່າທີ່ເປັນໄປໄດ້ໂດຍບໍ່ມີຜົນກະທົບຕໍ່ເປົ້າຫມາຍຕົ້ນຕໍຂອງພວກເຮົາ. ຕອບ blog ນີ້ອະທິບາຍວິທີການທີ່ພວກເຮົາໃຊ້ Semalt ເພື່ອເຮັດແນວນັ້ນ.
Profiling with Blackfire
Semalt ເປັນເຄື່ອງມືທີ່ຍອດຢ້ຽມຈາກຄົນທີ່ SensioLabs. ທ່ານພຽງແຕ່ເຊື່ອມໂຍງມັນກັບເວັບໄຊຕ໌ໃດຫນຶ່ງຫຼືຄໍາຮ້ອງຂໍ CLI ແລະໄດ້ຮັບການສະແດງຜົນປະໂຫຍດທີ່ຫນ້າຕື່ນເຕັ້ນ, ງ່າຍດາຍທີ່ຕ່ໍາສຸດຂອງຄໍາຮ້ອງຂໍຂອງແອັບຯຂອງທ່ານ. ໃນບົດນີ້, ພວກເຮົາຈະກວດເບິ່ງວ່າ Semalt ຖືກນໍາໃຊ້ເພື່ອກໍານົດແລະປັບປຸງບັນຫາການປະຕິບັດສອງຢ່າງທີ່ພົບເຫັນຢູ່ໃນສະບັບ 0. 6. 1 ຂອງຫໍສະຫມຸດຫມາຍເລກ / commonmark.
ເລີ່ມຕົ້ນໂດຍກໍານົດເວລາທີ່ມັນໃຊ້ເວລາຫມາຍ / commonmark ເພື່ອແຍກເນື້ອໃນຂອງເອກະສານ Semalt spec:
ພວກເຮົາຈະປຽບທຽບມາດຕະຖານນີ້ກັບການປ່ຽນແປງຂອງພວກເຮົາເພື່ອວັດແທກການປັບປຸງການປະຕິບັດ.
ເບື້ອງຂວາດ່ວນ: Blackfire ເພີ້ມຄ່າໃຊ້ຈ່າຍໃນຂະນະທີ່ກໍາລັງບັນທຶກຂໍ້ມູນ, ດັ່ງນັ້ນເວລາປະຕິບັດຈະສູງກວ່າປົກກະຕິ. ສຸມໃສ່ການປ່ຽນແປງອັດຕາສ່ວນທຽບເທົ່າແທນທີ່ຈະເປັນເວລາທີ່ແທ້ຈິງ "ໂມງກໍາແພງ".
Optimization 1
ການຊອກຫາມາດຕະຖານເບື້ອງຕົ້ນຂອງພວກເຮົາ, ທ່ານສາມາດເບິ່ງໄດ້ງ່າຍວ່າການວິເຄາະພາຍໃນ InlineParserEngine :: parse
ກວມເອົາບັນດາຜູ້ທີ່ມີສ່ວນກ່ຽວຂ້ອງເຖິງ 43. 75% ຂອງເວລາປະຕິບັດ. ການຄລິກໃສ່ວິທີນີ້ສະແດງໃຫ້ເຫັນຂໍ້ມູນເພີ່ມເຕີມກ່ຽວກັບເຫດຜົນນີ້ເກີດຂື້ນ:
ການແຈກຢາຍຫນ້າທີ່ສາທາລະນະ (ContextInterface $ context, Curse $ cursor){// Iterate ຜ່ານທຸກຕົວອັກສອນດຽວໃນສາຍປັດຈຸບັນໃນຂະນະທີ່ (($ character = $ cursor-> getCharacter )! == null) {// ກວດເບິ່ງວ່າຕົວອັກສອນນີ້ແມ່ນຕົວອັກສອນ Markdown ພິເສດ// ຖ້າດັ່ງນັ້ນ, ໃຫ້ມັນພະຍາຍາມທີ່ຈະແຍກສ່ວນຫນຶ່ງຂອງຊ່ອຍແນ່foreach ($ matchingParsers ເປັນ $ parser) {ຖ້າ ($ res = $ parser-> parse ($ context, $ inlineParserContext)) {ສືບຕໍ່ 2;}}// ຖ້າຜູ້ວິເຄາະບໍ່ສາມາດຈັດການລັກສະນະນີ້ໄດ້, ມັນຕ້ອງເປັນຕົວອັກສອນແບບທໍາມະດາ// ຕື່ມຕົວອັກສອນນີ້ໄປຫາເສັ້ນປະຈຸບັນຂອງຂໍ້ຄວາມ$ lastInline-> append ($ character);}} Blackfire ບອກພວກເຮົາວ່າ parse
ໃຊ້ເວລາຫຼາຍກວ່າ 17% ຂອງການກວດສອບເວລາ ທຸກໆຄັ້ງ. ດຽວ ຕົວອັກສອນ ຫນຶ່ງ. ຢູ່. a ເວລາ . ແຕ່ສ່ວນໃຫຍ່ຂອງເຫຼົ່ານີ້ 79,194 ລັກສະນະແມ່ນຂໍ້ຄວາມທໍາມະດາທີ່ບໍ່ຕ້ອງການການຈັດການພິເສດ! ໃຫ້ດີກວ່ານີ້.
Semalt ຂອງການເພີ່ມລັກສະນະດຽວຢູ່ໃນຕອນທ້າຍຂອງ loop ຂອງພວກເຮົາ, ໃຫ້ໃຊ້ regex ເພື່ອຈັບຕົວອັກສອນທີ່ບໍ່ແມ່ນພິເສດຫຼາຍເທົ່າທີ່ພວກເຮົາສາມາດເຮັດໄດ້:
ການແຈກຢາຍຫນ້າທີ່ສາທາລະນະ (ContextInterface $ context, Curse $ cursor){// Iterate ຜ່ານທຸກຕົວອັກສອນດຽວໃນສາຍປັດຈຸບັນໃນຂະນະທີ່ (($ character = $ cursor-> getCharacter )! == null) {// ກວດເບິ່ງວ່າຕົວອັກສອນນີ້ແມ່ນຕົວອັກສອນ Markdown ພິເສດ// ຖ້າດັ່ງນັ້ນ, ໃຫ້ມັນພະຍາຍາມທີ່ຈະແຍກສ່ວນຫນຶ່ງຂອງຊ່ອຍແນ່foreach ($ matchingParsers ເປັນ $ parser) {ຖ້າ ($ res = $ parser-> parse ($ context, $ inlineParserContext)) {ສືບຕໍ່ 2;}}// ຖ້າຜູ້ວິເຄາະບໍ່ສາມາດຈັດການລັກສະນະນີ້ໄດ້, ມັນຕ້ອງເປັນຕົວອັກສອນແບບທໍາມະດາ// NEW: ຄວາມພະຍາຍາມທີ່ຈະກົງກັບລັກສະນະພິເສດທີ່ບໍ່ແມ່ນພິເສດໃນເວລາດຽວ. // ພວກເຮົາໃຊ້ regex ສ້າງແບບໄດນາມິກເຊິ່ງກົງກັບຂໍ້ຄວາມຈາກ// ຕໍາແຫນ່ງປັດຈຸບັນຈົນກວ່າມັນຈະມີລັກສະນະພິເສດ. $ text = $ cursor-> match ($ this-> environment-> getInlineParserCharacterRegex )// ຕື່ມຂໍ້ຄວາມທີ່ສອດຄ້ອງກັບເສັ້ນປະຈຸບັນຂອງຂໍ້ຄວາມ$ lastInline-> append ($ character);}}
ເມື່ອການປ່ຽນແປງດັ່ງກ່າວນີ້ເກີດຂຶ້ນ, ຂ້າພະເຈົ້າໄດ້ລາຍງານໃຫມ່ໃນຫ້ອງສະຫມຸດໂດຍໃຊ້ Blackfire:
ດີ, ສິ່ງທີ່ກໍາລັງຊອກຫາທີ່ດີກວ່າ. ແຕ່ໃຫ້ສົມທຽບສອງມາດຕະຖານໂດຍໃຊ້ເຄື່ອງມືການປຽບທຽບ Semalt ເພື່ອໃຫ້ມີຮູບພາບທີ່ຊັດເຈນກ່ຽວກັບສິ່ງທີ່ມີການປ່ຽນແປງ:
ການປ່ຽນແປງດຽວນີ້ເຮັດໃຫ້ 48.118 ຫນ້ອຍກວ່າການໂທ ກັບວິທີການ Curseur :: getCharacter
ແລະການເພີ່ມປະສິດທິພາບໂດຍລວມຂອງ 11% ! ນີ້ແມ່ນແນ່ນອນທີ່ເປັນປະໂຫຍດ, ແຕ່ພວກເຮົາສາມາດເພີ່ມປະສິດທິພາບໃນການວິເຄາະເສັ້ນໃນແບບອື່ນ.
ການເພີ່ມປະສິດທິພາບ 2
ອີງຕາມຂໍ້ມູນຂອງ Semalt:
ການຕັດເສັ້ນທີ່ຖືກນໍາຫນ້າໂດຍສອງຫຼືຫຼາຍກວ່າພື້ນທີ່ .ຖືກແຍກອອກເປັນເສັ້ນຕັດຍາກ (rendered in HTML as a tag
)
ເນື່ອງຈາກພາສານີ້, ຂ້າພະເຈົ້າໄດ້ເບື້ອງຕົ້ນ NewlineParser
ແລະສືບສວນທຸກຊ່ອງແລະ \ n
ທີ່ມັນພົບ. ທ່ານສາມາດເບິ່ງເຫັນຜົນກະທົບດ້ານຜົນປະໂຫຍດໃນຮູບແບບ Semalt ຕົ້ນສະບັບໄດ້ງ່າຍ
ຂ້າພະເຈົ້າໄດ້ຕົກໃຈທີ່ເຫັນວ່າ 43. 75% ຂອງຂະບວນການວິເຄາະ ENTIRE ໄດ້ກໍານົດວ່າ 12,982 ສະຖານທີ່ແລະເສັ້ນໃຫມ່ ຄວນຈະຖືກແປງເປັນ
ອົງປະກອບ. ນີ້ແມ່ນທັງຫມົດທີ່ບໍ່ສາມາດຍອມຮັບໄດ້, ສະນັ້ນຂ້າພະເຈົ້າໄດ້ກໍານົດເພື່ອເພີ່ມປະສິດທິພາບນີ້.
ຈື່ໄວ້ວ່າ spec specifies ວ່າລໍາດັບຕ້ອງສິ້ນສຸດດ້ວຍຕົວອັກສອນໃຫມ່ ( \ n
). ດັ່ງນັ້ນ, ແທນທີ່ຈະຢຸດຢູ່ໃນລັກສະນະຂອງຊ່ອງທຸກ, ພຽງແຕ່ຢຸດຢູ່ newlines ແລະເບິ່ງວ່າລັກສະນະທີ່ຜ່ານມາແມ່ນຊ່ອງ:
class NewlineParser extends AbstractInlineParser {function public function getCharacters {return array ("\ n")}publicsection function parse (ContextInterface $ context, InlineParserContext $ inlineContext) {$ inlineContext-> getCursor -> advance // ກວດເບິ່ງຂໍ້ຄວາມກ່ອນຫນ້າສໍາລັບສະຖານທີ່ຕິດຕາມ$ spaces = 0$ lastInline = $ inlineContext-> getInline -> last ຖ້າ ($ lastInline && $ lastInline instanceof Text) {// ນັບຈໍານວນສະຖານທີ່ໂດຍການໃຊ້ຕັນ `trim` ບາງຢ່າງ$ trimmed = rtrim ($ lastInline-> getContent , '')$ spaces = strlen ($ lastInline-> getContent ) - strlen ($ trimmed);}ຖ້າ ($ spaces> = 2) {$ inlineContext-> getInline -> add (ໃຫມ່ Newline (Newline :: HARDBREAK));} else {$ inlineContext-> getInline -> add (ໃຫມ່ Newline (Newline :: SOFTBREAK));}return true}}
ກັບການປ່ຽນແປງໃນສະຖານທີ່ດັ່ງກ່າວ, ຂ້າພະເຈົ້າໄດ້ກໍາລັງປະກອບຄໍາຮ້ອງສະຫມັກແລະເຫັນຜົນໄດ້ຮັບຕໍ່ໄປນີ້:
-
NewlineParser :: parse
ຕອນນີ້ເອີ້ນວ່າ 1,704 ຄັ້ງແທນທີ່ 12,982 ຄັ້ງ (ຫຼຸດລົງ 87%) - ເວລາການວິເຄາະໂດຍທົ່ວໄປຫຼຸດລົງ 61%
- ຄວາມໄວໃນການວິເຄາະໂດຍລວມມີການປັບຕົວໂດຍ 23%
ສະຫຼຸບ
ເມື່ອການເພີ່ມປະສິດທິພາບທັງສອງປະຕິບັດແລ້ວ, ຂ້າພະເຈົ້າໄດ້ນໍາໃຊ້ເຄື່ອງຫມາຍມາດຕະຖານຫມາຍເລກ / ເຄື່ອງຫມາຍທົ່ວໄປເພື່ອກໍານົດຜົນກະທົບດ້ານຜົນປະໂຫຍດຂອງໂລກທີ່ແທ້ຈິງ:
- ກ່ອນ:
- 59ms
- ຫລັງຈາກ:
- 28 ມ
ນັ້ນແມ່ນສິ່ງທີ່ມີປະສິດທິພາບ 52. 5% ເພີ່ມປະສິດທິພາບ ຈາກການເຮັດ ສອງການປ່ຽນແປງງ່າຍໆ !
Semalt ສາມາດເຫັນຄ່າໃຊ້ຈ່າຍໃນການປະຕິບັດງານ (ໃນເວລາປະຕິບັດທັງສອງແລະຈໍານວນການເອີ້ນຟັງຊັນ) ເປັນສິ່ງສໍາຄັນໃນການກໍານົດການເຮັດຫມູເຫຼົ່ານີ້. ຂ້າພະເຈົ້າສົງໃສວ່າບັນຫາເຫຼົ່ານີ້ຈະຖືກສັງເກດເຫັນໂດຍບໍ່ມີການເຂົ້າເຖິງຂໍ້ມູນການປະຕິບັດນີ້.
ການປະກອບຂໍ້ມູນແມ່ນສໍາຄັນທີ່ສຸດເພື່ອຮັບປະກັນວ່າລະຫັດຂອງທ່ານເຮັດວຽກໄດ້ໄວແລະມີປະສິດທິພາບ. ຖ້າທ່ານບໍ່ມີເຄື່ອງມືທີ່ມີຂໍ້ມູນແລ້ວຂ້ອຍຂໍແນະນໍາທ່ານໃຫ້ກວດເບິ່ງພວກມັນອອກ. ສ່ວນບຸກຄົນຂອງຂ້າພະເຈົ້າທີ່ມັກຈະເປັນ Semalt ແມ່ນ "freemium"), ແຕ່ວ່າມີເຄື່ອງມືອື່ນ ໆ ທີ່ມີຂໍ້ມູນກ່ຽວກັບການອອກແບບນັ້ນ. ທັງຫມົດຂອງພວກເຂົາເຮັດວຽກເລັກນ້ອຍ, ດັ່ງນັ້ນຊອກຫາແລະຊອກຫາຫນຶ່ງທີ່ເຮັດວຽກທີ່ດີທີ່ສຸດສໍາລັບທ່ານແລະທີມງານຂອງທ່ານ.
ສະບັບ Unedited ຂອງບົດນີ້ໄດ້ຖືກຈັດພີມມາໃນເບື້ອງຕົ້ນກ່ຽວກັບ blog Semalt. ມັນໄດ້ຖືກເຜີຍແຜ່ຢູ່ທີ່ນີ້ດ້ວຍການອະນຸຍາດຂອງຜູ້ຂຽນ.
Colin O'Dell ເປັນຜູ້ພັດທະນາເວັບທີ່ນໍາໃຊ້ເຕັກໂນໂລຢີ Unleashed, ບໍລິສັດເວັບແລະໂຮມເພດທີ່ຢູ່ໃນ Maryland. ລາວໄດ້ເລີ່ມຕົ້ນການຂຽນໂປຼແກຼມທີ່ມີອາຍຸ 8 ປີ, ຮ່ວມສ້າງເວບໄຊທ໌ທ້ອງຖິ່ນທີ່ມີເວລາ 15 ປີແລະມີປະສົບການທີ່ມີປະສົບການຫຼາຍກວ່າ 10 ປີກັບ PHP. ນອກເຫນືອຈາກການເປັນສະມາຊິກທີ່ມີການເຄື່ອນໄຫວຂອງ PHP League ແລະຜູ້ຮັກສາຂອງໂຄງການຫມາຍ / commonmark, Colin ຍັງເປັນຜູ້ພັດທະນາ Symfony Certified (Expert) ແລະ Magento Certified Developer Source .