ฉันจะป้องกันไม่ให้สายยาวมาก ๆ ทำให้ Emacs ทำงานช้าได้อย่างไร


72

ฉันเห็นประสิทธิภาพที่หลากหลายขึ้นอยู่กับจำนวนบรรทัดใหม่ที่มีในไฟล์ที่ฉันกำลังเยี่ยมชม

นี่คือตัวอย่าง ฉันมีไฟล์ JSON สองไฟล์:

$ wget https://github.com/Wilfred/ReVo-utilities/blob/a4bdc40dd2656c496defc461fc19c403c8306d9f/revo-export/dictionary.json?raw=true -O one_line.json
$ python -m json.tool <one_line.json >pretty_printed.json

นี่เป็นไฟล์ JSON สองไฟล์ที่มีเนื้อหาเดียวกัน one_line.jsonคือ 18MiB ของ JSON โดยไม่มีการขึ้นบรรทัดใหม่ pretty_printed.jsonมีการขึ้นบรรทัดใหม่และเพิ่มช่องว่างทำให้ 41MiB

อย่างไรก็ตามไฟล์ที่ใหญ่กว่าที่แบ่งออกเป็นหลายบรรทัดนั้นเร็วกว่ามากที่จะเปิดใน Emacs ทั้งในโหมด Javascript และโหมด Fundamental

ทำไม Emacs ถึงมีประสิทธิภาพต่ำเช่นนี้เนื่องจากมีความยาวน้อยกว่าจริง ๆ ? มีอะไรที่ฉันสามารถทำได้เพื่อปรับปรุงประสิทธิภาพโดยไม่ต้องฟอร์แมตข้อมูลภายนอก Emacs หรือไม่?


2
คำตอบไม่ได้จริงๆ แต่อาจจะมีการใช้งาน: View Large Files(VLF)เป็นโหมดย่อยที่มีวัตถุประสงค์เพื่อช่วยให้มีการแก้ไขไฟล์ขนาดใหญ่โดยการโหลดไว้ในแบตช์ คำแถลงการณ์ปฏิเสธความรับผิดชอบ: ฉันไม่เคยใช้มันและฉันไม่รู้ว่าจะจัดการกับสายยาวเป็นชุดหรือไม่
elemakil

3
การรู้พฤติกรรมแบบนี้และโดยเฉพาะอย่างยิ่งเมื่อพยายามป้องกันตัวเองจากการอ่านบันทึกซึ่งแยกออกเป็นเส้นยาวฉันมักจะทำอะไรบางอย่าง$ tail -f /some/file | fold -sในบัฟเฟอร์ของเชลล์ มันไม่ดีสำหรับการแก้ไขอย่างชัดเจน แต่ช่วยได้มากกับการอ่าน
wvxvw

คำตอบ:


50

การจัดการกับไลน์ของ Emacs นั้นไม่ได้รับการปรับให้เหมาะสม สำหรับการทำงานจำนวนหนึ่ง Emacs ต้องสแกนทั้งบรรทัดซ้ำ ๆ ตัวอย่างเช่นในการแสดงเส้น Emac ต้องค้นหาความสูงของเส้นซึ่งต้องใช้การสแกนทั้งเส้นเพื่อค้นหาสัญลักษณ์ที่สูงที่สุด นอกจากนี้การสแกนเพื่อแสดงผลแบบสองทิศทางจะกินเวลามาก คุณสามารถรับข้อมูลเพิ่มเติมได้เช่น docstring ของcache-long-line-scans(เปลี่ยนชื่อเป็นcache-long-scans24.4)

คุณสามารถลองและดูว่าการตั้งค่าbidi-paragraph-directionที่จะleft-to-rightช่วยเพิ่มความเร็วสำหรับคุณ [การตั้งค่าbidi-display-reorderingจะnilไม่มากหรือน้อยเหมือนกัน แต่มีความหมายเฉพาะสำหรับวัตถุประสงค์ภายใน / การแก้จุดบกพร่อง] สิ่งนี้จะลบผู้สนับสนุนที่สำคัญหนึ่งรายไปยังการสแกนบรรทัด แต่ไม่ใช่เพียงคนเดียวที่น่าเศร้า

ตัวเลือกที่ดีที่สุดคือการเพิ่มบรรทัดใหม่ คุณสามารถไพพ์ไฟล์ JSON ผ่านเช่นpython -c 'import json, sys ; json.dump(json.load(sys.stdin), sys.stdout, indent=2)'เพื่อเพิ่มบรรทัดใหม่และปรับปรุงความสามารถในการอ่านโดยทั่วไป


4
จากความอยากรู้นี่เป็นสิ่งที่ไม่สามารถปรับปรุงอัลกอริทึมได้หรือไม่?
PythonNut

9
เมื่อเลือกโครงสร้างข้อมูลพื้นฐานของตัวแก้ไขคุณต้องเลือกระหว่างข้อดีและข้อเสียบางอย่าง Emacs ใช้บัฟเฟอร์ช่องว่างซึ่งเป็นโครงสร้างข้อมูลที่มีประสิทธิภาพพื้นที่สูงสำหรับการแทรกและการลบ แต่มันทำให้การดำเนินงานแบบบรรทัดช้าลงเมื่อคุณต้องสแกนตามลำดับเพื่อขึ้นบรรทัดใหม่ Emacs สามารถใช้โครงสร้างข้อมูลที่แตกต่างกัน แต่นั่นจะทำให้การทำงานอื่นช้าลง Emacs ใช้แคชบรรทัดแล้ว แต่ก็ไม่ได้ช่วยในทุกสถานการณ์ ดังนั้นไม่ได้ปรับปรุงอัลกอริทึมอย่างง่ายดาย แต่การทำโปรไฟล์และการปรับให้เหมาะสมไม่เคยเจ็บปวด :-)
Jorgen Schäfer

4
(setq-default bidi-display-reordering nil)- ผู้ใช้บางคนอาจไม่ทราบว่านี่เป็นตัวแปรบัฟเฟอร์ในเครื่องซึ่งอาจต้องมีการตั้งค่าเริ่มต้นตามขอบเขตที่ผู้ใช้ต้องการให้เป็นแบบโกลบอล ฉันหวังว่าฉันจะได้เพิ่มว่าในinit.elปีที่ผ่านมาของฉัน... แต่อย่างน้อยก็มีตอนนี้ ขอบคุณมาก!!!
กฎหมาย

ในกรณีของฉันมันไม่ได้เป็นตัวเพิ่มขนาดใหญ่ (เส้น json ยาวจริง ๆ กับตัวเอกสาร base64) แต่ช่วยได้มากในการแช่แข็ง beign
anquegi

1
ผู้ดูแลระบบ Emacs คนปัจจุบัน Eli ผู้เขียนรหัส BIDI เขียนสิ่งนี้เกี่ยวกับการปิดเครื่องbidi-display-reordering: "ความคิดเห็นหนึ่งที่ฉันมีคือการปิดใช้งานการแสดงผล bidi-display-reordering ... ทำให้เอ็นจิ้นการแสดงผลอยู่ในสถานะที่ไม่ได้ทดสอบ และแม้กระทั่งข้อผิดพลาด (เพราะบางส่วนของรหัสถูกเขียนภายใต้สมมติฐานว่าตัวแปรนี้ไม่เคยไม่มี)
Clément

18

ฉันทำการทดลองสั้น ๆ กับสิ่งนี้โดยใช้ jquery แบบย่อ font-lock-modeและflycheck-modeทั้งสองมีส่วนทำให้ช้าเป็นได้และjs2-mode และมีผลเล็กน้อย เมื่อฉันปิดโหมดที่แตกต่างกันทั้งหมดแม้ว่าประสิทธิภาพจะค่อนข้างเร็ว ใช้และเริ่มต้นการปิดการใช้งานโหมดที่แตกต่างที่มีการเปิดใช้งานหรือพยายามเพียงแค่เปลี่ยนไปprettify-symbols-modeline-number-modecolumn-number-modeC-h mfundamental-mode

การใช้ที่น่าสนใจhexl-modeฉันสามารถบินผ่านไฟล์ได้โดยไม่มีปัญหาใด ๆ แต่คอลัมน์นั้นค่อนข้างสั้น น่าเสียดายที่visual-line-modeชะลอตัวลงจริงๆ

ฉันเดาว่าตารางไวยากรณ์ยินดีที่จะหยุดการประมวลผลที่จุดสิ้นสุดของบรรทัดและเมื่อทุกอย่างอยู่ในบรรทัดเดียวมันจะแยกส่วนทุกอย่างในการอัพเดททุกครั้ง


2
คุณสามารถเปิดรายงานข้อผิดพลาดในตัวติดตามของ Flycheck ได้หรือไม่ ฉันค่อนข้างมั่นใจว่าเราไม่ต้องการบรรทัดยาวที่ทำให้เกิดปัญหาและ Emacs + Flycheck ไม่ควรเลวร้ายยิ่งกว่า Emacs (ซึ่งยังไม่ดีพอ)
Clément

16

ฉันได้อัปโหลดhttp://www.emacswiki.org/emacs/OverLongLineMode แล้ว

ไลบรารีนี้ช่วยให้คุณสามารถตั้งค่าขีดจำกัดความยาวบรรทัดที่ง่ายกว่าตัวแปรที่fundamental-modeจะใช้สำหรับไฟล์แทนโหมดปกติ (สำหรับโหมดการเขียนโปรแกรมเท่านั้น)

อาจมีการเพิ่มบางสิ่งในบรรทัดเหล่านี้ลงใน Emacs โดยค่าเริ่มต้น แต่นี่อาจเป็นวิธีแก้ปัญหาชั่วคราวสำหรับปัญหาหลักของ Emacs ที่ชะลอการรวบรวมข้อมูลเมื่อพบไฟล์ดังกล่าว

nb นี่คือการปรับปรุงรหัสที่ฉันโพสต์ครั้งแรกในคำตอบนี้ แต่ก็ยังอยู่ระหว่างการพัฒนา การทดสอบมีน้อยมาก ยินดีรับฟังความคิดเห็น

คำแนะนำสำหรับโหมดที่สำคัญอื่น ๆ (นอกเหนือจากcss-mode) ที่ไม่ได้รับการprog-modeถ่ายทอดเพื่อการสนับสนุนจะได้รับการต้อนรับด้วยเช่นกัน


1
ตอนนี้ปรับปรุงเพิ่มเติมและเปลี่ยนชื่อเป็น so-long.el :) (ลิงก์ด้านบนจะเปลี่ยนเส้นทาง) มีอีกมากมายที่สามารถทำได้ด้วยสิ่งนี้ แต่มีประโยชน์และประโยชน์ 100% ตามที่เป็นอยู่
phils

นี่เป็นทางออกที่ดีจริงๆ (ชอบที่จะเห็นใน MELPA) แต่อินสแตนซ์ Emac ของฉันยังคงช้ามากเมื่อเปิด one_line.json ฉันคิดว่ามันจะเร็วขึ้นอย่างมีนัยสำคัญหากไม่ได้เปิดใช้งานโหมดหลักครั้งแรก
Wilfred Hughes

3
อ่านมันอีกครั้งและใช้ไฟล์ one_line.json ของคุณจากคำถามฉันยอมรอการตั้งค่าเริ่มต้น Emacs 25.3 และ 26.0.91 เพื่อตอบสนองหลังจากขอให้พวกเขาเปิดไฟล์นั้น (หลังจากรอนานกว่าหนึ่งนาที) ในขณะที่ฉันเอง config ด้วยso-long.elactive จะเปิดไฟล์ภายในไม่เกิน 2 วินาที การแก้ไขไฟล์จริงๆยังคงเป็นปัญหาอย่างมหาศาล (เช่นการพยายามย้ายไปที่ 'บรรทัดถัดไป' จะใช้เวลานานมาก) แต่อย่างไรก็ตามสิ่งนี้กลับคืนความเชื่อของฉันในประโยชน์ของห้องสมุดที่ฉันเขียนดังนั้นฉันควรดำเนินการตามแผนต่อไป เพิ่มเข้าไปใน GNU ELPA ...
Phils

1
อยู่ใน (M) ELPA หรือยัง
binki

3
รายงานสถานะ: เวอร์ชั่น 1.0 จากso-long.el(พร้อมการปรับปรุงจำนวนมาก) รวมอยู่ในเวอร์ชันการพัฒนาปัจจุบันของ Emacs 27 และจะพร้อมใช้งาน (สำหรับเวอร์ชั่นก่อนหน้าของ Emacs) ผ่าน GNU ELPA ในอนาคตอันใกล้
phils

7

font-lockฉันหวังว่าคุณจะพบว่าแตกต่างกันคือเนื่องจาก เมื่อจะทำการฟอนต์บนชุดย่อยของไฟล์ที่สามารถมองเห็นได้ในหน้าต่างมันจะดำเนินการโดยการขยายขอบเขตการฟอนต์เป็นครั้งแรกเพื่อที่จะรวมหน่วยความหมายแบบเต็ม ดูfont-lock-extend-region-functionsรหัสสำหรับสิ่งนี้ เป็นเรื่องปกติที่จะรวมการขยายพื้นที่เพื่อรวมบรรทัดเต็ม เมื่อบรรทัดมีความยาวมากสิ่งนี้สามารถนำไปสู่การทำแบบอักษรในเนื้อหาที่มีขนาดใหญ่กว่าที่มองเห็นได้จริง

นอกจากนี้เมื่อบรรทัดใหม่เองมีข้อมูลเชิงความหมายบางครั้งการขาดงานของพวกเขาอาจหมายถึงรูปแบบ regexp สำหรับการล็อคแบบอักษรต้องสแกนเพิ่มเติมเพื่อตรวจสอบว่าตรงกันหรือไม่


7

ฉันมักจะคลี่บรรทัดยาว ๆ และเยื้องด้วยแท็ก (เช่น HTML, XML, JSON)

เพื่อให้การดำเนินการดังกล่าวเป็นไปได้ฉันเพิ่ม:

(setq line-number-display-limit large-file-warning-threshold)
(setq line-number-display-limit-width 200)

(defun my--is-file-large ()
  "If buffer too large and my cause performance issue."
  (< large-file-warning-threshold (buffer-size)))

(define-derived-mode my-large-file-mode fundamental-mode "LargeFile"
  "Fixes performance issues in Emacs for large files."
  ;; (setq buffer-read-only t)
  (setq bidi-display-reordering nil)
  (jit-lock-mode nil)
  (buffer-disable-undo)
  (set (make-variable-buffer-local 'global-hl-line-mode) nil)
  (set (make-variable-buffer-local 'line-number-mode) nil)
  (set (make-variable-buffer-local 'column-number-mode) nil) )

(add-to-list 'magic-mode-alist (cons #'my--is-file-large #'my-large-file-mode))

ผมแยกเส้น regex สำหรับ XML C-M-% >< RET >NL< RET !มัน

หลังจาก Emacs แบ่งสายยาว - เป็นไปได้ที่จะเปิดใช้งานรหัสจำนวนมาก*-modesและเยื้อง

สำหรับหมายเหตุ: วิธีการป้องกันการชะลอตัวลงเมื่อกระบวนการที่ต่ำกว่าสร้างสายยาว?


4

ฉันสร้างโซลูชันของตัวเองสำหรับปัญหานี้ที่นี่: https://github.com/rakete/too-long-lines-mode

ฉันไม่พอใจกับโซลูชัน phils ซึ่งเปลี่ยนบัฟเฟอร์ด้วยบรรทัดที่ยาวมากเป็นโหมดพื้นฐานฉันต้องการโซลูชันที่ให้ฉันทำการเน้นไวยากรณ์และคุณลักษณะโหมดหลักอื่น ๆ ดังนั้นฉันจึงสร้างโหมดรองที่ใช้การซ้อนทับเพื่อซ่อนอักขระส่วนใหญ่ของบรรทัดที่ยาวเกินไป

สิ่งนี้สามารถแก้ไขปัญหาและทำให้ emac สามารถใช้งานได้แม้จะอยู่ในบัฟเฟอร์ที่มีเส้นยาวมากโดยไม่ต้องถอยกลับไปที่โหมดพื้นฐาน


2

ในการตั้งค่า Emacs ของฉันฉันมีโหมดที่มี fontification font-lock-defaultsที่กำหนดเองคือที่ที่ผมตั้ง หน้าเดียวจะใช้เวลา 30 วินาทีในการแสดงส่วนของบรรทัดอักขระ 30000 การชะลอตัวนี้ได้รับการแก้ไขโดยลดการย้อนรอย regexp แทน:

  (". * ลงท้ายด้วยคำสั่งที่ไม่สมบูรณ์ *" 0 font-lock-comment-face)

ทำเช่นนี้

  ("^. \ {1,80 \} จบลงด้วยคำสั่งที่ไม่สมบูรณ์ *" 0 font-lock-comment-face)

นี่ไม่ใช่คำตอบสำหรับคำถามซึ่งไม่เฉพาะเจาะจงเกี่ยวกับการfont-lock-defaultsจับคู่หรือ regexp
Drew

1
@Drew น้อยกว่าอุดมคติ regex กำลังทำ font-lock ช้าบนบรรทัดที่ยาวแม้ว่า ...
wasamasa

1
@wasamasa: ใช่ คำถามนั้นกว้างเกินไป IMO มีหลายสิ่งหลายอย่างที่สามารถทำให้ Emacs ทำงานช้าลง (และการกระทำใด?) เมื่อมีสายยาวเข้ามาเกี่ยวข้อง
ดึง

3
ฉันไม่คิดว่าคำถามคือกว้าง ("ทำไมเส้นยาวทำให้ Emacs ช้า") ฉันไม่คิดว่าคำตอบไม่ได้ตอบคำถาม (" เหตุผลหนึ่งข้อที่เป็นไปได้คือ regexps ที่ไม่ดี") คำตอบอื่น ๆ สามารถตอบสนองด้วยเหตุผลอื่น การเปิดไฟล์ที่มีบรรทัดที่ยาวไม่ได้ครอบคลุมหัวข้อเพียงเพราะมันอาจเป็นปัญหาด้วยเหตุผลหลายประการบางครั้งคุณมีไฟล์ดังกล่าวและคุณต้องดูพวกเขาโดยเฉพาะอย่างยิ่งการใช้ Emacs
Tarsius

1

ในบัฟเฟอร์โหมดเชลล์ของฉัน (Mx shell) ฉันพบว่าตัวเองไปป์sed -r 's/(.{2000}).*/\1/' -uไลน์เพื่อหลีกเลี่ยงบรรทัดที่ยาว


ส่วนนี้จะตอบคำถามส่วนที่สอง: วิธีปรับปรุงประสิทธิภาพ มันไม่ได้กล่าวถึงส่วนแรก (ซึ่งก็โอเค): " ทำไม Emacs ถึงมีประสิทธิภาพต่ำเช่นนี้ด้วยสายยาว "
ดึง

0

ฉันใช้ฟังก์ชั่นต่อไปนี้เพื่อเปิดdired-modeไฟล์ขนาดใหญ่ที่มีเส้นยาว:

(defun dired-find-file-conservatively ()
   (interactive)
   (let ((auto-mode-alist nil))
     (dired-find-file)
     ;; disable costly modes
     (fundamental-mode)
     (setq-local bidi-display-reordering nil)
     (when (boundp 'smartparens-mode)
       (smartparens-mode -1))))

(define-key dired-mode-map (kbd "S-<return>") 'dired-find-file-conservatively)

0

นี่คือวิธีแก้ปัญหาที่นำมาจากemacs-devel :

(add-hook 'find-file-hook
          (defun my-find-file-care-about-long-lines ()
            (save-excursion
              (goto-char (point-min))
              (when (and (not (eq major-mode 'image-mode))
                         (search-forward-regexp ".\\{2000\\}" 50000 t)
                         (y-or-n-p "Very long lines detected - enable 
longlines-mode? "))
                (require 'longlines)
                (longlines-mode +1)))))

ใน Emacs ณ 24.4 ได้ทำเครื่องหมายเป็นละทิ้งlonglines-mode visual-line-mode
Alexander I.Grafov

อย่างไรก็ตามคุณสมบัติทั้งสองนี้ทำสิ่งต่าง ๆ เบื้องหลังและvisual-line-modeไม่ได้ช่วยแก้ไขปัญหาที่เป็นปัญหาในขณะที่longlines-modeทำ ด้วยเหตุผลนี้ฉันคาดว่า longlines.el จะถูกกู้คืนสู่สถานะที่ไม่สนับสนุน
phils
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.