การทำงานของ Async ในองค์กร Babel


14

มีการปรับแต่งทั่วไปที่ดีของ org-babel เพื่อให้ทำงานแบบอะซิงโครนัสหรือไม่? เมื่อเร็ว ๆ นี้ฉันวางแผนที่จะใช้ MATLAB ผ่าน org-babel แต่ฉันต้องการแบบ async เนื่องจากการคำนวณบางอย่างใช้เวลานาน

ฉันไม่ต้องการปรับแต่ง ob-matlab เท่านั้น นี่เป็นเพราะฉันคิดว่ามันควรจะทำในระดับของกรอบแทนที่จะเป็นโปรแกรม กล่าวอีกนัยหนึ่งการปรับเปลี่ยนแบบเดียวกันควรเปิดใช้งานคุณลักษณะ async สำหรับส่วนขยายภาษาอื่นเช่นภาษา R

ใครบ้างมีทางออกที่ดี? จนถึงตอนนี้ฉันได้ลองasync.elและdeferred.elปรับเปลี่ยนorg-babel-execute-safely-maybeที่สามารถพบได้ในob-core.elขณะนี้


คำแนะนำอีกอย่างคือสามารถส่ง babel block ไปที่หน้าจอหรือ tmux
stardiviner

ฉันไม่เคยใช้มัน แต่ฟังดูเป็นไปได้ ขอบคุณ
diadochos

ฉันเดาว่าฉันยอมรับคำตอบของตัวเองเนื่องจากยังไม่มีคำตอบอื่นใดโพสต์ในช่วงหนึ่งเดือนที่ผ่านมา
diadochos

คำตอบ:


6

ฉันได้ค้นพบแล้วว่าการวางไข่กระบวนการ Emacs ใหม่เป็นวิธีแก้ปัญหา

นี่คือสิ่งที่ฉันได้ทำ

1. เพิ่มฟังก์ชั่นเพื่อเริ่มกระบวนการ emacs ภายนอก

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. เพิ่มไฟล์กำหนดค่าเพื่อโหลดในกระบวนการ emacs ใหม่

ฟังก์ชั่นด้านบนเริ่ม emacs ใน--batchโหมด ดังนั้น init.el ปกติจะไม่ถูกโหลด

แต่เราต้องการสร้างไฟล์กำหนดค่าที่สั้นกว่า (เพื่อโหลดพา ธ และอื่น ๆ )

เส้นทางไปยังไฟล์กำหนดค่าใหม่ของเราจะถูกจัดเก็บไว้ในasync-emacs-repl-org-babel-init-fileข้อมูลโค้ดด้านบน

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

ที่นี่เรา ...

  1. เพิ่มเส้นทางของแพ็คเกจ
  2. บอกโหมดองค์กรเพื่อไม่ให้ถามว่าจะเรียกใช้งานการบล็อกรหัส
  3. บอกองค์กรที่จำเป็นต้องใช้ภาษา

เชิงอรรถ 1: หากไม่มีการตั้งค่านี้การประเมินผลจะล้มเหลว "No org-babel-execute function for $lang!"

เชิงอรรถ 2: แน่นอนคุณสามารถโหลด init.el ปกติแทนที่จะสร้างไฟล์ config ใหม่ได้หากต้องการ ทำได้โดยการเพิ่มของคุณ(setq org-babel-async-init-file "~/.emacs.d/init") init.elแต่ฉันคิดว่าการสร้างไฟล์กำหนดค่าสำหรับงานนี้ตรงไปตรงมามากกว่า

3. นอกจากนี้ ...

เพิ่มใน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)

เพิ่มใน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")

เพิ่มในorg-babel-async-init.el (คุณอาจไม่ต้องการสิ่งเหล่านี้สำหรับ 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"))

เพิ่มในorg-babel-async-init.el (คุณอาจไม่ต้องการสิ่งเหล่านี้สำหรับ Julia, R และภาษาอื่น ๆ ที่ใช้ 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. การใช้งาน

(หลังจากการตั้งค่าด้านบน)

  1. เลื่อนเคอร์เซอร์ไปที่ข้อมูลโค้ดที่คุณต้องการดำเนินการ
  2. เรียกใช้M-x my/async-emacs-repl-org-babel-execute(แทนที่จะทำC-c C-c) สิ่งนี้จะเริ่มต้นกระบวนการ Emacs ภายนอกเป็นเซิร์ฟเวอร์ REPL หากจำเป็นจากนั้นเรียกใช้บล็อกต้นทางที่คุณอยู่

กิตติกรรมประกาศ

ฉันได้เรียนรู้แนวคิดของการเริ่มต้นกระบวนการ emacs สำหรับการประเมิน org-babel จากโพสต์นี้ ฉันอยากจะขอบคุณผู้เขียน

ความคิดเห็นสำหรับการปรับแต่ง

ความคิดที่นี่ง่าย เริ่ม emacs ใหม่ประมวลผลเป็น REPL สำหรับ Elisp ให้ทำfind-fileไปยังแฟ้ม .org เดียวกันกับที่เราได้รับการแก้ไขgoto-lineไปยังจุดเคอร์เซอร์เดียวกันทำงาน,org-babel-execute-src-block save-bufferหยุดออกจนกว่าผู้ใช้จะหยุดกระบวนการ (มิฉะนั้นกราฟจะหายไปทันทีหลังจากที่พวกเขาแสดง) หนึ่งสามารถคิดเกี่ยวกับการขยายโดย:

  • การใช้โหมดองค์กรC-c C-cแทนการใช้ฟังก์ชั่นด้วยมือ / การตั้งค่าปุ่มลัดใหม่ (ซึ่งสามารถทำได้โดยคำแนะนำ)
  • การสลับชื่อกระบวนการอย่างมีเงื่อนไขตาม: ตัวแปรเซสชันและภาษา
  • การสลับไฟล์ init แบบมีเงื่อนไขขึ้นอยู่กับภาษา

ในความเป็นจริงความสำเร็จของวิธีการนี้ดูเหมือนว่าฉันจะแสดงวิธีทั่วไปในการพัฒนาคุณลักษณะ async ใน Emacs การสร้างเลเยอร์ "คำสั่ง" เพิ่มสคริปต์เพื่อทำงานและมีกรอบการทำงานสำหรับการเริ่มต้นและนำกระบวนการ emacs กลับมาใช้ใหม่ เช่นเดียวกับกรอบ Symfony ของ PHP (PHP ไม่มีเธรด) มีคุณลักษณะคำสั่ง

แก้ไขประวัติ

รหัส refactored (2016-04-02) โซลูชันนำกระบวนการ Emacs มาใช้ใหม่ (2016-04-02) โซลูชันตอนนี้ง่ายขึ้นและมีเพียงหนึ่งinteractiveคำสั่งให้เรียกใช้ (2016-04-02. เพิ่มการกำหนดค่า (2016-04-12)


คุณเคยเห็นasync.el?
PythonNut

ใช่ฉันมี. มันเริ่มต้นกระบวนการใหม่ของ Emacs และเรียกใช้lambdaฟังก์ชันที่ให้ไว้ ฉันไม่ได้ใช้สำหรับการแก้ปัญหานี้เพราะฉันหาวิธีส่งข้อมูลไปยังกระบวนการใหม่ไม่ได้ การสื่อสารกระบวนการเป็นสิ่งจำเป็นหากคุณต้องการใช้คุณลักษณะ: session ของ org-babel
diadochos

ขอขอบคุณที่ทำงานกับโซลูชันนี้ ฉันลองแล้ว แต่ได้รับข้อความแสดงข้อผิดพลาด: TERM=vt200 emacs --batch -nw --eval '(load "~/.emacs.d/org-babel-async-init")' --eval '(while t (print (eval (read))))': exited abnormally with code 255.ขออภัยนี่ควรเป็นความคิดเห็นไม่ใช่คำตอบ แต่ฉันมีคะแนนไม่เพียงพอ
mhartm

หลังจากดำเนินการแล้วคุณเห็นบัฟเฟอร์ชื่อ " org-babel-async " หรือไม่ หากคุณสามารถค้นหาได้บัฟเฟอร์นั้นอาจมีข้อมูลเพิ่มเติมเกี่ยวกับข้อผิดพลาด "ออกอย่างผิดปกติด้วยรหัส 255" โดยทั่วไปจะเกิดขึ้นเมื่อโปรแกรมที่คุณต้องการเรียกใช้ในกระบวนการ emacs ที่เกิดขึ้นล้มเหลว วิธีที่เป็นไปได้: 1) ตรวจสอบว่าคุณมีไฟล์ที่ระบุในไฟล์ / async-emacs-repl-org-babel-init-my ของฉันหรือไม่ หากไม่เป็นเช่นนั้นให้สร้างขึ้นใหม่ตามที่อธิบายไว้ข้างต้น 2) ตรวจสอบว่าคุณมีรายการภาษาที่คุณต้องการใช้org-babel-do-load-languagesหรือไม่ 3) #+SRC_BEGINบล็อกที่คุณกำลังเรียกใช้มีข้อบกพร่อง
diadochos

เอาล่ะเพื่อให้ปัญหาคือการที่ฉันต้องบันทึกไฟล์ org ของฉันก่อนที่จะใช้M-x my/async-emacs-repl-org-babel-executeมิฉะนั้น "org-Babel-async" ...t/Dropbox/org/work.org locked by maarhart@htkl... (pid 68694): (s, q, p, ?)? Please type q, s, or p; or ? for helpบัฟเฟอร์จะบ่น: ดังนั้นถ้าสิ่งนี้สามารถแก้ไขได้มันจะยอดเยี่ยม ขอบคุณสำหรับสิ่งนี้มันน่าทึ่งมาก! โดยวิธีการมันเป็นไปได้ที่จะผูกไว้กับมันC-c C-cหรือมันจะขัดแย้งกับโหมด org-?
mhartm

4

สำหรับการอ้างอิงในอนาคตและไลบรารีแบบไม่ต้องแจ้งล่วงหน้า ฉันจะยอมรับคำตอบนี้เพราะสิ่งเหล่านี้เป็นคำตอบล่าสุด

OB-async

นี่คือห้องสมุดที่ใช้ async.el https://github.com/linktohack/ob-async

org-Babel-EVAL ใน repl

โซลูชันอื่นของฉัน (มีให้ใน melpa): https://github.com/diadochos/org-babel-eval-in-repl

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.