プロパティで照合する場合のorg-map-entriesの高速化


8

質問org-map-entriesプロパティマッチングが非常に遅いのはなぜですか、それを高速化するにはどうすればよいですか?

背景:私は比較的単純な用途がありorg-map-entriesます:タグgoalと特定の優先順位(例:)を持つすべての組織アジェンダエントリから(整数分で)作業を取得しますB

(org-map-entries #'hw-org-get-effort-in-minutes "goal+PRIORITY=\"B\"" 'agenda)

これはひどく遅く、私の〜12,000行の議題ファイルに1分以上かかります。

ただし、PRIORITYフィルターからを削除してgoalsタグ付きアイテムを選択すると、ほぼ即座に完了します。

のようにフィルターを設定することもできますが、フィルターはgoal/DONE非常に迅速に完了しますが、私がそのようなgoals+EFFORT>0ことをすると、1分以上かかるようになります。一般に、プロパティのマッチングは非常に遅いようです。

私はチートの回避策を見つけました:を使用して、マップされた関数内のプロパティを非常にすばやく一致させることができますorg-entry-get。これを実行すると、実行は1秒未満です。これはばかげているようですが、うまくいけばもっと良い方法があると思いますが、少なくともそれはうまくいきます!

すでに試してみました(benchmark 1000 (hw-org-effort-to-minutes "1:20"))戻るので"Elapsed time: 0.000019s"、私の機能はあまり貢献していないと思います。

によるとprofiler、CPU時間の最大40%がによって使用されcond、最大29%が要素の解析に起因しています(org-element--current-element)。次の2つの最大の寄与は14%と13%であるため、40%がcond問題の大部分を占めているようです。ヘッダー(タグ、TODO)とヘッダー+ボディ(プロパティ)の解析のみが異なる場合を除き、プロパティマッチャーを使用して要素の解析がより頻繁に行われる理由がわかりません。

回答:


2

速度を改善する1つの方法は、一致するすべてのエントリの作業を収集する一時バッファーでアジェンダファイルの内容を一度解析することですgoal+PRIORITY="B"(テスト1を参照)。〜10K行の場合、org-map-entries(テスト2)を使用した場合の「経過時間:1.340006s」と比較して、「経過時間:0.052280s」が得られました。より良い結果をorg-map-entries得るには、かなり速いテスト3を試すことができます。Emacsバージョン26.2およびOrgモードバージョン9.2.4でテストされています。

テスト1(最速)

(org-duration-from-minutes
 (apply '+ (let (efforts
                 (regexp (concat org-effort-property ":\s*\\(.+\\)")))
             (with-temp-buffer
               (mapcar #'insert-file-contents org-agenda-files)
               (goto-char (point-min))
               (while (re-search-forward regexp nil t)
                 (let ((effort (match-string 1)))
                   (save-excursion
                     (outline-previous-heading)
                     (when (and (member "goal" (org-get-tags))
                                (= (and (looking-at org-heading-regexp)
                                        (org-get-priority (match-string 0)))
                                1000))
                    (push (org-duration-to-minutes effort) efforts))))))
          efforts)))

テスト2(最も遅い)

(org-duration-from-minutes
 (apply '+ (org-map-entries
            (lambda ()
              (org-duration-to-minutes
               (org-entry-get nil org-effort-property)))
            "goal+PRIORITY=\"B\""
            'agenda)))

テスト3(かなり良い)

(org-duration-from-minutes
 (apply '+ (org-map-entries
            (lambda ()
              (if (re-search-forward (concat org-effort-property ":\s*\\(.+\\)")
                                     (save-excursion
                                       (org-end-of-meta-data)
                                       (point))
                                     t)
                  (let ((effort (match-string 1)))
                    (outline-previous-heading)
                    (when (looking-at org-complex-heading-regexp)
                      (let ((priority (match-string 3))
                            (tags (match-string 5)))
                        (if (and (string= priority "[#B]")
                                 (string-match ":goal:" tags))
                            (org-duration-to-minutes effort)
                          0))))
                0))
            nil 'agenda)))
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.