Thực hiện Async trong org babel


14

Có một tùy chỉnh chung tốt của org-babel để chạy không đồng bộ? Gần đây tôi có kế hoạch sử dụng MATLAB thông qua org-babel, nhưng tôi muốn nó theo cách không đồng bộ, vì một số tính toán làm mất thời gian.

Tôi không muốn chỉ tùy chỉnh ob-matlab. Điều này là do tôi nghĩ rằng nó nên được thực hiện ở cấp độ khung thay vì một ứng dụng. Nói cách khác, một sửa đổi tương tự sẽ kích hoạt tính năng async cho các tiện ích mở rộng ngôn ngữ khác, ví dụ ngôn ngữ R.

Có ai có một giải pháp tốt? Cho đến nay tôi đã cố gắng async.elcũng như deferred.elsửa đổi org-babel-execute-safely-maybecó thể được tìm thấy ob-core.eltại thời điểm này.


Một gợi ý khác là có thể vượt qua khối babel để sàng lọc hoặc tmux.
stardiviner

Tôi chưa bao giờ thực hiện điều đó, nhưng nó có vẻ có thể. Cảm ơn.
diadochos

Tôi đoán tôi đang chấp nhận câu trả lời của riêng mình vì không có bất kỳ giải pháp nào khác được đăng trong một tháng qua.
diadochos

Câu trả lời:


6

Cho đến nay tôi đã phát hiện ra rằng sinh ra một quy trình Emacs mới là một giải pháp.

Đây là những gì tôi đã làm.

1. Thêm một chức năng để bắt đầu một quá trình emacs bên ngoài.

init.el

(defvar my/async-emacs-repl-org-babel-init-file "~/.emacs.d/org-babel-async-init" "File to load on executing async babel evaluation.")

(defun my/async-emacs-repl--start (process-name init-file)
  "Start a new Emacs process as a REPL server."
  (async-shell-command (concat
                        "TERM=vt200 emacs --batch -nw"
                        " --eval '(load \"" init-file "\")'"
                        " --eval '(while t (print (eval (read))))'"
                        )
                       process-name))

(defun my/async-emacs-repl--org-babel--start-server ()
  "Starts an Emacs process for async org-babel execution."
  (my/async-emacs-repl--start "*org-babel-async*" my/async-emacs-repl-org-babel-init-file))

(defun my/async-emacs-repl--org-babel--start-if-not-exists ()
  "Starts an Emacs process if the process does not exist."
  (if (not (get-buffer-process "*org-babel-async*")) (my/async-emacs-repl--org-babel--start-server)))

(defun my/async-emacs-repl--org-babel--execute--build-command (file-name line-number)
  "Build the command for executing `org-babel-execute-src-block'."
  (concat
   "(progn"
   " (find-file \"" file-name "\")"
   " (revert-buffer t t)"
   " (goto-line " (number-to-string line-number) ")"
   " (org-babel-execute-src-block t)"
   " (save-buffer)"
   ")"
   "\n"))

(defun my/async-emacs-repl--org-babel--execute (process-name file-name line-number)
  "Sends the command to the server to run the code-block the cursor is at."
  (process-send-string
   process-name
   (my/async-emacs-repl--org-babel--execute--build-command file-name line-number)))

(defun my/async-emacs-repl-org-babel-do-execute ()
  "Run org babel execution at point."
  (my/async-emacs-repl--org-babel--execute "*org-babel-async*" (buffer-file-name) (line-number-at-pos)))

(defun my/async-emacs-repl-org-babel-execute ()
  "Run by the user. Executes command. Starts buffer if not exists."
  (interactive)
  (save-buffer)
  (my/async-emacs-repl--org-babel--start-if-not-exists)
  (my/async-emacs-repl-org-babel-do-execute))

2. Thêm tệp cấu hình để tải trong quy trình emacs mới.

Các chức năng trên bắt đầu emacs trong --batchchế độ. Do đó, init.el bình thường sẽ không được tải.

Thay vào đó, chúng tôi muốn tạo một tệp cấu hình ngắn hơn (để tải đường dẫn, v.v.).

Đường dẫn đến tệp cấu hình mới của chúng tôi được lưu trữ trong async-emacs-repl-org-babel-init-fileđoạn trích ở trên.

org-babel-async-init.el

;; 1
(package-initialize)

;; 2
(setq org-confirm-babel-evaluate nil)

;; 3
(let ((my/org-babel-evaluated-languages
       '(emacs-lisp
         ditaa
         python
         ruby
         C
         matlab
         clojure
         sh
         dot
         plantuml)))
  (org-babel-do-load-languages
   'org-babel-load-languages
   (mapcar (lambda (lang)
             (cons lang t))
           my/org-babel-evaluated-languages)))

Ở đây chúng tôi ...

  1. Thêm đường dẫn gói.
  2. Nói với chế độ org để không hỏi có thực thi khối mã hay không.
  3. Nói với org-babel những ngôn ngữ cần thiết.

Chú thích 1: Không có cài đặt này, việc đánh giá sẽ thất bại với "No org-babel-execute function for $lang!"

Chú thích 2: Tất nhiên bạn có thể tải init.el bình thường thay vì tạo tệp cấu hình mới, nếu bạn muốn. Làm điều đó bằng cách thêm (setq org-babel-async-init-file "~/.emacs.d/init")vào của bạn init.el. Nhưng tôi nghĩ việc tạo một tệp cấu hình cho tác vụ này đơn giản hơn.

3. Ngoài ra ...

Thêm vào init.el

;; This will stop the new process buffer from getting focus.
(setq display-buffer-alist (append display-buffer-alist '(("*org-babel-async*" display-buffer-no-window))))

;; This will automatically show the result section.
(global-auto-revert-mode 1)

Thêm vào org-babel-async-init.el

;; This will skip the "Save anyway?" confirmation of automatically saving the file when you also edited the buffer from Emacs while an asynchronous process is running.
(defun advice:verify-visited-file-modtime (orig-func &rest args) t)
(advice-add 'verify-visited-file-modtime :around 'advice:verify-visited-file-modtime)

;; This will skip the "Select coding system" prompt that appears when the result is inserted. This may vary among environments.
(setq coding-system-for-write 'utf-8)

;; This will skip the "changed on disk; really edit the buffer?" checking.
(defun ask-user-about-supersession-threat (fn) "blatantly ignore files that changed on disk")

Thêm vào org-babel-async-init.el (bạn có thể không cần những thứ này. Đây là cho MATLAB)

;; This will set MATLAB cli path.
(setq-default matlab-shell-command "/Applications/MATLAB_R2016a.app/bin/matlab")
;; The MATLAB cli path can be obtained by running `fullfile(matlabroot, 'bin')` in your MATLAB.

;; This will stop MATLAB from showing the splash (the MATLAB logo) at the beginning.
(setq-default matlab-shell-command-switches '("-nodesktop" "-nosplash"))

Thêm vào org-babel-async-init.el (bạn có thể không cần những thứ này. Chúng dành cho Julia, R và các ngôn ngữ khác sử dụng ESS.)

;; This will enable :session header in Julia and other languages that use ESS (Emacs speaks statistics).
(load "/path/to/ess-site")
;; This will suppress ESS from prompting for session directory.
(setq ess-ask-for-ess-directory nil)

4. Cách sử dụng

(Sau khi thiết lập ở trên.)

  1. Di chuyển con trỏ đến đoạn mã bạn muốn thực thi.
  2. Chạy M-x my/async-emacs-repl-org-babel-execute(thay vì làm C-c C-c). Điều này sẽ bắt đầu một quá trình Emacs bên ngoài như một máy chủ REPL nếu cần, và sau đó thực thi khối nguồn bạn đang ở.

Sự nhìn nhận

Tôi đã học được ý tưởng bắt đầu một quá trình emacs để đánh giá org-babel từ bài đăng này . Tôi xin cảm ơn tác giả.

Nhận xét để tùy chỉnh

Ý tưởng ở đây rất đơn giản. Bắt đầu một quá trình emacs mới dưới dạng REPL cho Elisp, thực hiện find-filevới cùng một tệp .org mà chúng tôi đang chỉnh sửa, goto-lineđến cùng một điểm con trỏ, chạy org-babel-execute-src-block, save-buffer. Dừng thoát cho đến khi người dùng dừng quá trình (Nếu không, biểu đồ sẽ biến mất ngay sau khi chúng được hiển thị). Một cách tự nhiên có thể nghĩ về việc mở rộng điều này bằng cách:

  • Sử dụng chế độ org C-c C-cthay vì chạy các chức năng bằng tay / cài đặt một tổ hợp phím mới (có thể đạt được bằng lời khuyên).
  • Điều kiện chuyển đổi tên quá trình theo: biến phiên và ngôn ngữ
  • Điều kiện chuyển đổi các tập tin init dựa trên ngôn ngữ.

Trên thực tế, sự thành công của phương pháp này đối với tôi dường như đang cho thấy một cách chung để phát triển các tính năng không đồng bộ trong Emacs. Tạo một lớp "lệnh", thêm tập lệnh để thực hiện các tác vụ và có một khung để bắt đầu và sử dụng lại các quy trình emacs. Giống như khung công tác Symfony của PHP (PHP không có chủ đề) có các tính năng Lệnh.

Chỉnh sửa lịch sử

Mã tái cấu trúc (2016-04 / 02). Giải pháp hiện đang sử dụng lại một quy trình Emacs (2016-04-02). Giải pháp hiện đã được đơn giản hóa và chỉ có một interactivelệnh để chạy (2016-04-02. Đã thêm cấu hình (2016-04-12).


Bạn đã thấy async.elchưa
PythonNut

Vâng tôi có. Về cơ bản, nó bắt đầu một quá trình mới của Emacs và chạy lambdachức năng được cung cấp cho nó. Tôi đã không sử dụng nó cho giải pháp này vì tôi không thể tìm cách gửi dữ liệu đến quy trình mới. Giao tiếp quá trình là cần thiết nếu bạn muốn sử dụng tính năng: session của org-babel.
diadochos

Cảm ơn đã làm việc trên giải pháp này. Tôi đã thử nhưng tôi nhận được thông báo lỗi này: TERM=vt200 emacs --batch -nw --eval '(load "~/.emacs.d/org-babel-async-init")' --eval '(while t (print (eval (read))))': exited abnormally with code 255.Xin lỗi, đây phải là một nhận xét và không phải là một câu trả lời, nhưng tôi chỉ không có đủ điểm.
mhartm

Sau khi thực hiện điều đó, bạn có thấy một bộ đệm có tên " org-babel-async " không? Nếu bạn có thể tìm thấy một, bộ đệm đó có thể chứa nhiều thông tin hơn về lỗi. "Thoát bất thường với mã 255" thường xảy ra khi chương trình bạn muốn chạy trên quy trình emacs sinh ra không thành công. Các cách có thể ra: 1) Kiểm tra xem bạn có tệp được chỉ định trong tệp / async-emacs-repl-org-babel-init-file không. Nếu bạn không, hãy tạo một cái như mô tả ở trên. 2) Kiểm tra xem bạn đã liệt kê ngôn ngữ bạn muốn sử dụng chưa org-babel-do-load-languages. 3) #+SRC_BEGINKhối bạn đang thực thi có lỗi.
diadochos

Được rồi, vì vậy vấn đề là tôi cần lưu tệp org của mình trước khi chạy M-x my/async-emacs-repl-org-babel-execute, nếu không bộ đệm "org-babel-async" sẽ phàn nàn : ...t/Dropbox/org/work.org locked by maarhart@htkl... (pid 68694): (s, q, p, ?)? Please type q, s, or p; or ? for help. Vì vậy, nếu điều này có thể được giải quyết, nó sẽ là tuyệt vời. Dù sao cũng cảm ơn vì điều này, nó thật tuyệt vời! Nhân tiện, nó có thể liên kết nó với nó C-c C-chay nó sẽ xung đột với chế độ org?
mhartm

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.