Büyük arabelleklerde "satır başında" sayısını elde etmek için daha hızlı bir yöntem


19

İşlev line-number-at-pos(yaklaşık 50 kez tekrarlandığında), nokta tamponun sonuna yakın olduğunda, yarı büyük tamponlarda (örn., 50.000 satır) belirgin bir yavaşlamaya neden olur. Yavaşlama ile toplam yaklaşık 1,35 saniyelik toplam demek istiyorum.

elispSatırları saymak ve arabellek üstüne gitmek için % 100 bir funciton kullanmak yerine , mod satırında görünen satır numarasından sorumlu yerleşik C yeteneklerine giren bir melez yöntemle ilgilenirim. Mod satırında görünen satır numarası, arabellek boyutundan bağımsız olarak ışık hızında gerçekleşir.


İşte bir test fonksiyonu:

(defmacro measure-time (&rest body)
"Measure the time it takes to evaluate BODY.
http://lists.gnu.org/archive/html/help-gnu-emacs/2008-06/msg00087.html"
  `(let ((time (current-time)))
     ,@body
     (message "%.06f" (float-time (time-since time)))))

(measure-time
  (let* (
      line-numbers
      (window-start (window-start))
      (window-end (window-end)))
    (save-excursion
      (goto-char window-end)
      (while
        (re-search-backward "\n" window-start t)
        (push (line-number-at-pos) line-numbers)))
    line-numbers))

Yanıtlar:


17

Deneyin

(string-to-number (format-mode-line "%l"))

Emacs Lisp El Kitabında açıklanan % -Constructs komutunu kullanarak başka bilgiler de alabilirsiniz .

Uyarı:

Wasamasa ve Stefan'ın işaret ettiği sınırlamalara ek olarak (aşağıdaki yorumlara bakın), görüntülenmeyen arabellekler için çalışmaz.

Bunu dene:

(with-temp-buffer
  (dotimes (i 10000)
    (insert (format "%d\n" i)))
  (string-to-number (format-mode-line "%l")))

ve karşılaştır

(with-temp-buffer
  (dotimes (i 10000)
    (insert (format "%d\n" i)))
  (line-number-at-pos))

Evet, bu 1,35 saniyeden 0,003559'a düşürüldü! Çok teşekkür ederim - büyük beğeni topluyor! :)
hukukçu

6
Bu yöntemin size "??" vereceğini unutmayın. buradaline-number-display-limit-width bulduğum gibi varsayılan başına 200 değerine ayarlanan aşan satırlar için .
wasamasa

3
IIRC, son yeniden görüntülemeden bu yana tamponda değişiklikler yapılmışsa sonuç güvenilir olmayabilir.
Stefan

Ben ikinci mektup öyle ki cevap testleri değiştirmek için gerekli olacağına inanıyorum ideğiştirilir (string-to-number (format-mode-line "%l"))ilk test için, ve ikinci harf iile değiştirilir (line-number-at-pos)ikinci test için.
hukukçu

5

nlinum.el aşağıdakileri kullanır:

(defvar nlinum--line-number-cache nil)
(make-variable-buffer-local 'nlinum--line-number-cache)

;; We could try and avoid flushing the cache at every change, e.g. with:
;;   (defun nlinum--before-change (start _end)
;;     (if (and nlinum--line-number-cache
;;              (< start (car nlinum--line-number-cache)))
;;         (save-excursion (goto-char start) (nlinum--line-number-at-pos))))
;; But it's far from clear that it's worth the trouble.  The current simplistic
;; approach seems to be good enough in practice.

(defun nlinum--after-change (&rest _args)
  (setq nlinum--line-number-cache nil))

(defun nlinum--line-number-at-pos ()
  "Like `line-number-at-pos' but sped up with a cache."
  ;; (assert (bolp))
  (let ((pos
         (if (and nlinum--line-number-cache
                  (> (- (point) (point-min))
                     (abs (- (point) (car nlinum--line-number-cache)))))
             (funcall (if (> (point) (car nlinum--line-number-cache))
                          #'+ #'-)
                      (cdr nlinum--line-number-cache)
                      (count-lines (point) (car nlinum--line-number-cache)))
           (line-number-at-pos))))
    ;;(assert (= pos (line-number-at-pos)))
    (setq nlinum--line-number-cache (cons (point) pos))
    pos))

mod işlevinde aşağıdaki ekstra yapılandırma ile:

(add-hook 'after-change-functions #'nlinum--after-change nil t)

1
Ah ... Bu sabah erken saatlerde kütüphanenizi düşünüyordum. line-number-at-posKonstantin tarafından cevap ile değiştirilebilir olabilir ve bu daha da bunun daha önceden onun Kütüphanenizi hızlandıracaktı - özellikle büyük tamponlarda. count-linesKonstantin yöntemi kullanılarak da düzeltilmelidir. Hatta bu işlevleri düzeltmek için report-emacs-bug yardım hattına bir öneri gönderimi göndermeyi düşünüyordum.
hukukçu
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.