Làm cách nào để ngăn chặn các dòng cực dài làm cho Emacs chậm?


72

Tôi thấy hiệu suất rất đa dạng tùy thuộc vào có bao nhiêu dòng mới trong tệp tôi đang truy cập.

Đây là một ví dụ. Tôi có hai tệp 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

Đây là hai tệp JSON có cùng nội dung. one_line.jsonlà 18MiB của JSON mà không có bất kỳ dòng mới nào. pretty_printed.jsoncó dòng mới và khoảng trắng được thêm vào, làm cho nó 41MiB.

Tuy nhiên, tệp lớn hơn được chia thành nhiều dòng nhanh hơn để mở trong Emacs, cả ở chế độ Javascript và chế độ Cơ bản.

Tại sao Emacs có hiệu suất kém như vậy với các dòng dài, vì nó thực sự ít byte hơn? Có điều gì tôi có thể làm để cải thiện hiệu suất mà không cần định dạng lại dữ liệu bên ngoài Emacs không?


2
Không thực sự là một câu trả lời nhưng có thể được sử dụng: View Large Files(vlf) là một chế độ nhỏ nhằm giúp chỉnh sửa các tệp lớn bằng cách tải chúng theo lô . Tuyên bố miễn trừ trách nhiệm: Tôi chưa bao giờ sử dụng nó và tôi không biết liệu nó có xử lý các hàng dài theo đợt hay không.
elemakil

3
Biết loại hành vi này, và đặc biệt là khi cố gắng bảo vệ bản thân khỏi việc đọc một bản ghi phát ra một dòng dài, tôi thường làm một cái gì đó giống như $ tail -f /some/file | fold -strong một bộ đệm vỏ. Điều này rõ ràng không tốt cho việc chỉnh sửa, nhưng giúp ích rất nhiều cho việc đọc.
wvxvw

Câu trả lời:


50

Việc xử lý các hàng dài của Emacs không được tối ưu hóa tốt. Đối với một số hoạt động, Emacs phải quét toàn bộ dòng liên tục. Ví dụ, để hiển thị một dòng, Emacs phải tìm ra chiều cao của dòng, yêu cầu quét toàn bộ dòng để tìm glyph cao nhất. Ngoài ra, quét để hiển thị hai chiều ngốn rất nhiều thời gian. Bạn có thể nhận được một số thông tin bổ sung, ví dụ, chuỗi doc của cache-long-line-scans(được đổi tên cache-long-scanstrong 24.4).

Bạn có thể thử và xem nếu thiết lập bidi-paragraph-directionđể left-to-rightcải thiện tốc độ cho bạn [thiết bidi-display-reorderingđể nil, không nhiều hơn hoặc ít hơn như nhau nhưng chỉ dành cho mục đích / gỡ lỗi nội bộ]. Điều này loại bỏ một đóng góp đáng kể cho quét dòng, nhưng thật đáng buồn không phải là người duy nhất.

Tùy chọn tốt nhất là thêm dòng mới. Bạn có thể dẫn một tệp JSON thông qua ví dụ python -c 'import json, sys ; json.dump(json.load(sys.stdin), sys.stdout, indent=2)'để thêm dòng mới và cải thiện khả năng đọc nói chung.


4
Vì tò mò, đây có phải là thứ không thể cải thiện về mặt thuật toán?
PythonNut

9
Khi chọn cấu trúc dữ liệu cơ bản của trình soạn thảo, bạn phải chọn giữa ưu và nhược điểm nhất định. Emacs sử dụng bộ đệm khoảng cách , là cấu trúc dữ liệu hiệu quả không gian cao để chèn và xóa, nhưng nó làm cho các hoạt động dựa trên dòng chậm hơn khi bạn phải quét tuần tự cho một dòng mới. Emacs có thể sử dụng một cấu trúc dữ liệu khác, nhưng điều đó sẽ làm cho các hoạt động khác chậm hơn. Emacs đã sử dụng bộ đệm dòng, nhưng điều đó không thực sự giúp ích trong mọi tình huống. Vì vậy, không dễ dàng cải thiện thuật toán, nhưng hồ sơ và tối ưu hóa không bao giờ bị tổn thương. :-)
Jorgen Schäfer

4
(setq-default bidi-display-reordering nil)- một số người dùng có thể không nhận ra rằng đây là biến cục bộ đệm, có thể cần cài đặt mặc định ở mức độ mà người dùng muốn nó là toàn cục. Tôi ước tôi đã thêm nó vào những init.elnăm trước của tôi ... nhưng ít nhất là bây giờ nó đã ở đó. Cảm ơn bạn rất nhiều!!!
luật

Trong trường hợp của tôi, đó không phải là một sự bất cập lớn (các dòng json thực sự dài với thân tài liệu cơ
sở64

1
Người duy trì Emacs hiện tại, Eli, người đã viết mã BIDI, đã viết điều này về việc tắt bidi-display-reordering: "Một nhận xét tôi có là việc vô hiệu hóa tính năng sắp xếp lại hiển thị giá thầu đặt công cụ hiển thị ở trạng thái không được kiểm tra và có thể gây ra sự không nhất quán và thậm chí các lỗi (vì một số phần của mã được viết theo giả định rằng biến này không bao giờ là không). "
Clément

18

Tôi đã thực hiện một số thí nghiệm ngắn với điều này bằng cách sử dụng một bản sao được rút gọn của jquery. font-lock-modeflycheck-modecả hai đã đóng góp cho sự chậm chạp, như đã làm js2-mode, và prettify-symbols-mode. line-number-modecolumn-number-modecó ảnh hưởng nhỏ. Khi tôi đã tắt tất cả các chế độ khác nhau mặc dù hiệu suất tương đối ổn. Sử dụng C-h mvà bắt đầu vô hiệu hóa các chế độ khác nhau được bật hoặc thử chỉ cần chuyển sang fundamental-mode.

Thú vị khi sử dụng hexl-modetôi có thể lướt qua tệp mà không gặp vấn đề gì, mặc dù rõ ràng các cột khá ngắn. Thật không may visual-line-modethực sự làm mọi thứ chậm lại.

Tôi đoán là bảng cú pháp rất vui khi dừng xử lý ở cuối dòng và khi tất cả nằm trên một dòng, nó phải lặp lại mọi thứ trên mỗi bản cập nhật.


2
Bạn có thể mở một báo cáo lỗi trên trình theo dõi của Flycheck không? Tôi khá chắc chắn rằng chúng tôi không muốn các dòng dài gây ra sự cố và Emacs + Flycheck không nên tệ hơn Emacs (vẫn còn khá tệ).
Clément

16

Tôi đã tải lên http://www.emacswiki.org/emacs/OverLongLineMode

Thư viện này cho phép bạn đặt các ngưỡng độ dài dòng đơn giản mà vượt qua đó một biến thể fundamental-modesẽ được sử dụng cho một tệp thay vì chế độ thông thường (chỉ dành cho chế độ lập trình).

Có khả năng một cái gì đó dọc theo các dòng này có thể được thêm vào Emacs theo mặc định, nhưng đây có thể là một cách giải quyết tạm thời cho vấn đề chính của Emacs làm chậm việc thu thập dữ liệu khi gặp phải một tệp như vậy.

nb Đây là một cải tiến về mã mà tôi đã đăng ban đầu trong câu trả lời này, nhưng vẫn đang tiến hành. Kiểm tra đã được tối thiểu. Bình luận được hoan nghênh.

Các đề xuất cho các chế độ chính khác (ngoài css-mode) không prog-modehỗ trợ theo mặc định cũng được hoan nghênh.


1
Bây giờ được cải thiện hơn nữa, và đáng xấu hổ đổi tên thành so-long.el :) (liên kết ở trên sẽ chuyển hướng). Có nhiều thứ có thể được thực hiện với điều này, nhưng nó là 100% chức năng và hữu ích.
phils

Đây là một giải pháp thực sự tốt (rất thích nhìn thấy nó trên MELPA), nhưng ví dụ Emacs của tôi vẫn cực kỳ chậm khi mở one_line.json. Tôi nghĩ rằng nó sẽ nhanh hơn đáng kể nếu lần đầu tiên nó không kích hoạt chế độ chính.
Wilfred Hughes

3
Đọc lại điều này và sử dụng tệp one_line.json của bạn từ câu hỏi, tôi đã từ bỏ chờ đợi cấu hình mặc định Emacs 25.3 và 26.0.91 để trả lời sau khi yêu cầu họ mở tệp đó (sau khi chờ hơn một phút), trong khi riêng tôi cấu hình với so-long.elkích hoạt mở tệp trong dưới 2 giây. Trên thực tế, việc chỉnh sửa tệp vẫn còn nhiều vấn đề (ví dụ: cố gắng chuyển sang 'dòng tiếp theo' sẽ mất một thời gian rất dài), tuy nhiên điều này sẽ khôi phục niềm tin của tôi vào tính hữu ích của thư viện tôi đã viết, vì vậy tôi nên tiếp tục kế hoạch của mình thêm nó vào GNU ELPA ...
phils

1
Có phải trong (M) ELPA chưa?
biley

3
Báo cáo trạng thái: phiên bản 1.0 của so-long.el(với nhiều cải tiến) được bao gồm trong các phiên bản phát triển hiện tại của Emacs 27, và sẽ có sẵn (đối với các phiên bản trước của Emacs) thông qua GNU ELPA trong tương lai gần.
phils

7

Tôi hy vọng bạn sẽ thấy rằng sự khác biệt là do font-lock. Khi phông chữ được thực hiện trên tập hợp con của tệp có thể nhìn thấy trong cửa sổ, trước tiên, nó sẽ tiến hành mở rộng vùng phông chữ sao cho nó sẽ bao gồm các đơn vị ngữ nghĩa đầy đủ. Xem font-lock-extend-region-functionsmã cho điều này. Điều này là phổ biến để bao gồm việc mở rộng khu vực để bao gồm các dòng đầy đủ. Khi các dòng quá dài, điều này có thể dẫn đến việc phông chữ được thực hiện trên một đoạn nội dung lớn hơn rất nhiều so với thực tế có thể nhìn thấy.

Ngoài ra, khi bản thân dòng mới có thông tin ngữ nghĩa, sự vắng mặt của chúng đôi khi có thể có nghĩa là các mẫu regrec cho khóa phông chữ phải quét thêm để xác định xem chúng có khớp hay không.


7

Tôi thường hủy đăng ký các dòng dài và thụt lề bằng các thẻ (như HTML, XML, JSON).

Để thực hiện các hoạt động như vậy có thể tôi thêm:

(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))

Tôi chia dòng theo regex, cho XML nó : C-M-% >< RET >NL< RET !.

Sau khi Emacs phân chia các dòng dài - có thể kích hoạt nhiều mã *-modesvà thụt lại mã.

Đối với lưu ý: Làm thế nào để ngăn chặn sự chậm lại khi một quá trình kém hơn tạo ra các dòng dài?


4

Tôi đã tạo giải pháp của riêng mình cho vấn đề này tại đây: https://github.com/rakete/too-long-lines-mode

Tôi không hài lòng với giải pháp phils chuyển bộ đệm có các dòng rất dài sang chế độ cơ bản, tôi muốn một giải pháp cho phép tôi tiếp tục tô sáng cú pháp và các tính năng chế độ chính khác. Vì vậy, tôi đã tạo một chế độ nhỏ sử dụng lớp phủ để ẩn hầu hết các ký tự của các dòng quá dài.

Điều đó giải quyết vấn đề và làm cho emacs có thể sử dụng được ngay cả trong các bộ đệm với các dòng rất dài, mà không phải quay lại chế độ cơ bản.


2

Trong thiết lập Emacs của tôi, tôi có một chế độ với phông chữ tùy chỉnh, tức là nơi tôi đặt font-lock-defaults. Một trang xuống sẽ sử dụng 30 giây để hiển thị một phần của dòng 30000 ký tự. Sự chậm lại này đã được khắc phục bằng cách giảm quay lui regrec. Thay vì:

  (". * đã kết thúc bằng một lệnh chưa hoàn thành *" 0 font-lock-comment-face)

làm cái này

  ("^. \ {1,80 \} đã kết thúc bằng một lệnh chưa hoàn thành *" 0 font-lock-comment-face)

Đây không phải là một câu trả lời cho câu hỏi, mà không cụ thể về font-lock-defaultshoặc kết hợp regrec.
Drew

1
@Drew Ít hơn regex lý tưởng làm cho khóa chữ chậm trên các hàng dài mặc dù ...
wasamasa

1
@wasamasa: Vâng. Câu hỏi tự nó quá rộng, IMO. Có rất nhiều điều có thể làm chậm Emacs (và cho hành động nào?) Khi có hàng dài.
Drew

3
Tôi không nghĩ câu hỏi là mở rộng ("tại sao những dòng dài làm Emacs chậm")? Tôi cũng không nghĩ rằng câu trả lời không giải quyết được câu hỏi (" một lý do có thể là biểu thức chính quy tối ưu"). Các câu trả lời khác có thể giải quyết các lý do khác. Mở một tệp với các dòng dài không phải là một chủ đề rộng vì chỉ có thể có vấn đề vì nhiều lý do, đôi khi bạn có các tệp đó và bạn phải xem chúng, tốt nhất là sử dụng Emacs.
tarsius

1

Trong bộ đệm chế độ shell của tôi (Mx shell), tôi thấy mình có đường ống sed -r 's/(.{2000}).*/\1/' -uđể tránh các hàng dài.


Điều này trả lời phần thứ hai của câu hỏi: làm thế nào để cải thiện hiệu suất. Nó không đề cập đến phần đầu tiên (điều này ổn): " Tại sao Emacs có hiệu suất kém như vậy với các dòng dài ?"
vẽ

0

Tôi sử dụng chức năng sau để mở trong dired-modecác tệp lớn với các dòng dài:

(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

Đây là một cách giải quyết, được lấy từ 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)))))

Trong Emacs vào ngày 24.4, longlines-modeđã bị đánh dấu là lỗi thời visual-line-mode.
Alexander I.Grafov

Tuy nhiên, hai tính năng thực hiện những điều rất khác nhau đằng sau hậu trường, và visual-line-modekhông giúp gì cho vấn đề đang được đề cập, trong khi đó longlines-modethì không. Vì lý do này, tôi hy vọng rằng longlines.el sẽ được khôi phục về trạng thái không phản đối.
phils
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.