org babel의 비동기 실행


14

비동기 적으로 실행하기 위해 org-babel에 대한 일반적인 사용자 정의가 있습니까? 최근에는 org-babel을 통해 MATLAB을 사용할 계획이지만 일부 계산에는 시간이 걸리기 때문에 비동기 방식으로 원합니다.

ob-matlab 만 사용자 정의하고 싶지 않습니다. 응용 프로그램 대신 프레임 워크 수준에서 수행해야한다고 생각하기 때문입니다. 즉, 동일한 수정으로 다른 언어 확장 (예 : R 언어)에 비동기 기능을 사용할 수 있어야합니다.

누구든지 좋은 해결책이 있습니까? 지금까지 나는 현재 발견 할 수있는 것을 수정 하려고 시도 async.el했다 .deferred.elorg-babel-execute-safely-maybeob-core.el


또 다른 힌트는 babel 블록을 screen 또는 tmux로 전달할 수 있다는 것입니다.
stardiviner

나는 그것을 구현 한 적이 없지만 가능한 것 같습니다. 감사.
diadochos

지난 한 달 동안 게시 된 다른 솔루션이 없기 때문에 내 대답을 수락하고있는 것 같습니다.
diadochos 2016 년

답변:


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 프로세스에서로드 할 구성 파일을 추가하십시오.

위의 기능은 --batch모드 에서 emacs를 시작 합니다. 따라서 일반 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. 코드 블록을 실행할지 묻지 않도록 org-mode에 지시하십시오.
  3. 어떤 언어가 필요한지 org-babel에게 알려주십시오.

각주 1 :이 설정이 없으면 평가가 실패합니다 "No org-babel-execute function for $lang!"

각주 2 : 물론 원하는 경우 새 구성 파일을 만드는 대신 일반 init.el을로드 할 수 있습니다. 에 추가하여이 작업 (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)

에 추가 조직 - 바벨 - 비동기 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. 필요한 경우 REPL 서버로 외부 Emacs 프로세스를 시작한 다음 현재 소스 블록을 실행합니다.

감사의 말

이 게시물 에서 org-babel 평가를 위해 emacs 프로세스를 시작하는 아이디어를 배웠 습니다 . 저자에게 감사드립니다.

사용자 정의에 대한 주석

여기서 아이디어는 간단합니다. Elisp의 REPL로 새 emacs 프로세스를 시작하고 find-file편집중인 동일한 .org 파일 goto-line에서 동일한 커서 포인트로 run org-babel-execute-src-block,을 수행하십시오 save-buffer. 사용자가 프로세스를 중지 할 때까지 종료를 중지하십시오 (그렇지 않으면 그래프가 표시된 후 즉시 사라짐). 자연스럽게 이것을 확장하여 생각할 수 있습니다 :

  • C-c C-c수동으로 기능을 실행하는 대신 org-mode를 사용 하거나 새로운 키 바인드를 설정합니다 (이는 조언으로 얻을 수 있음).
  • : session 변수 및 언어에 따라 조건부로 프로세스 이름 전환
  • 언어에 따라 init 파일을 조건부로 전환합니다.

사실,이 접근법의 성공은 Emacs에서 비동기 기능을 개발하는 일반적인 방법을 보여주고있는 것 같습니다. "명령"레이어를 생성하고, 작업을 수행 할 스크립트를 추가하고, emacs 프로세스를 시작하고 재사용하기위한 프레임 워크를 갖습니다. PHP의 Symfony 프레임 워크와 마찬가지로 (PHP에는 스레드가 없음) 명령 기능이 있습니다.

기록 편집

리팩토링 된 코드 (2016-04-02). 솔루션은 이제 Emacs 프로세스를 재사용합니다 (2016-04-02). 이제 솔루션이 단순화되었으며 interactive실행할 명령 이 하나만 있습니다 (2016-04-02. 구성 추가 (2016-04-12).


봤어 async.el?
PythonNut

네, 있어요. 본질적으로 새로운 Emacs 프로세스를 시작하고 lambda주어진 기능을 실행 합니다. 새로운 프로세스로 데이터를 보내는 방법을 찾지 못해이 솔루션에 사용하지 않았습니다. org-babel의 : session 기능을 사용하려면 프로세스 통신이 필요합니다.
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) my / async-emacs-repl-org-babel-init-file에 지정된 파일이 있는지 확인하십시오. 그렇지 않은 경우 위에서 설명한대로 생성하십시오. 2) 사용할 언어를 나열했는지 확인하십시오 org-babel-do-load-languages. 3) #+SRC_BEGIN실행중인 블록에 버그가 있습니다.
diadochos

좋아, 문제는 실행하기 전에 내 조직 파일을 저장해야한다는 것입니다 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-corg-mode 에 바인딩 할 수 있습니까, 아니면 org-mode와 충돌 할 수 있습니까?
mhartm

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.