谈谈Emacs Lisp的异步

作者: 齐格Insight | 来源:发表于2016-07-09 15:42 被阅读466次

elisp的异步

elisp并没有提供好的异步操作,原生的语言级别只提供了一个创建异步子进程的函数。

异步子进程

elisp提供了一个创建异步子进程的函数start-process,这个函数返回一个process对象。该函数的语法如下:

start-process name buffer-or-name program &rest args

参数解释:

  1. name 表示子进程的名字,如果该名字对应的子进程已经存在。那么它将被修改为name<1>,这样使得它名字唯一。当然,如果name<1>也存在了,名字将被修改为name<2>,以此类推;
  2. buffer-or-name 与子进程相关联的buffer名字,并且,子进程的执行结果也会显示在这个buffer上;
  3. program 为要执行的程序,如果program为nil,那么不创建子进程,只创建一个buffer;同时,其他参数(args)也被无视;
  4. args 其他参数,将作为program的参数。

下面举一个例子:

(defun ab/test-start-process ()
  "test aysnc proecess"
  (interactive)
  (start-process "test-start-process" "*tsp*" "ls"
                 "-l" (file-truename "~/.spacemacs.d")))

然后,执行的结果将显示在*tsp*这个buffer里

异步子进程的结果*tsp*内容

process对象的操作

获得当前正在运行中的子进程列表,可采用list-processes这个函数,如下:

运行中的子进程列表
对start-process函数返回的process对象,elisp提供了以下操作函数:
  • 通过子进程名获得process对象,如果进程不存在,则返回nil
get-process name
  • 获得子进程的状态信息
process-status process-name

它的参数可为子进程对象子进程名子进程对应的buffer。这个函数返回的结果可能为:run/stop/exit/singal/open/closed/connect/failed/listen/nil。

  • 子进程是否alive
process-live-p process

如果子进程仍在alive,则返回non-nil。当一个子进程的状态为run, open, listen, connect 或 stop时,它被认为是alive的。

  • 子进程退出时的状态信息,如果子进程仍在alive,刚返回0
process-exit-status process

其他操作函数请参照手册。

async包

通过以上我们发现Emacs Lisp的异步操作真是很繁琐。要是我想异步地执行一个lambda函数?怎么办?
答:采用async这个异步包。该包可通过melpapopkit elpa软件源安装。
它显然是一个更好的选择。它的使用语法如下:

async-start START-FUNC FINISH-FUNC

其中第一个参数是子进程要执行的lambda函数,第二个参数为回调函数:
下面是其说明文档里给的一个例子:

(async-start
 ;; 在子进程中要执行的lambda函数
 (lambda ()
   (message "This is a test")
   (sleep-for 3)  ;; 休眠3s
   222)

 ;;当子进程执行完成后要执行的回调,子进程执行的结果将作为回调函数的参数
 (lambda (result)
   (message "Async process done, result should be 222: %s" result)))

如果去读async的源代码,你会发现它本质上调用的还是start-process这个函数。不过,它通过调用start-process启动了一个emacs子进程来执行lambda函数。所以,导致的一个问题是,通过async-start创建的emacs子进程并没有继承当前emacs运行环境的上下文(context)。

下面举一个我自己写的例子(用于异步更新本地repo):

(defun ab/git-code-update ()
  "update code async."
  (interactive)
  (async-start
   ;; 异步执行更新code操作
   (lambda ()
     (add-to-list 'load-path "~/.spacemacs.d/parts")
     (require 'aborn-log)
     (ab/log "exec-when-emacs-boot....")
     (let ((ab--git-project-list
            '("~/.emacs.d/" "popkit" "~/.spacemacs.d/" "piece-meal" "pelpa" "eden")))
       (dolist (elt ab--git-project-list)
         (let* ((working-directory
                 (if (or (string-prefix-p "/" elt) (string-prefix-p "~" elt))
                     elt
                   (concat "~/github/" elt "/")))
                (default-directory working-directory))
           (ab/log (shell-command-to-string "echo $PWD"))
           ;; 执行操作是异步的!
           (ab/log (shell-command-to-string "git pull"))))))
   (lambda (result)
     (message "finished ab/exec-when-emacs-boot,%s" result))))

在这个例子中aborn-log.el文件虽然已经在当前启动的emacs中load了,但在新创建的异步的emacs子进程中完全没有这个上下文(context)信息。因此,你不得不加入以下两行代码:

(add-to-list 'load-path "~/.spacemacs.d/parts")
(require 'aborn-log)

这样才能调用ab/log这个函数。

相关文章

  • 谈谈Emacs Lisp的异步

    elisp的异步 elisp并没有提供好的异步操作,原生的语言级别只提供了一个创建异步子进程的函数。 异步子进程 ...

  • 简介

    1. 为什么学习 Emacs Lisp 2. Lisp 的历史 3. Lisp 的特点 4. E...

  • Emacs资料汇总

    Emacs 官方手册 Emacs Lisp 15 分钟入门 从零开始——Emacs 安装配置使用教程 2015 E...

  • Emacs Lisp 学习(2)

    昨天, 学习了 Emacs Lisp 的一些基本的概念, 今天学习如何定义函数, 如何使用函数. 在 Emacs ...

  • emacs笔记

    前言 最初接触emacs是因为org-mode,后来学习lisp又把玩了几把。我还是无法放弃Lisp,就从emac...

  • Macos下spacemacs+slime+sbcl配置comm

    基本工具 spacemacs: 优秀的第三方 emacs 配置 slime: The Superior Lisp ...

  • **lisp** 学习笔记

    开发环境 开发环境: SBCLEmacsSlime:在emacs里面帮助进行common lisp开发的扩展qui...

  • Emacs Lisp 学习(1)

    这是一个读书笔记, 是我学习 Emacs Lisp 的笔记. 这是这个笔记的第一篇. 使用 Emacs 做编辑器的...

  • Emacs Lisp 学习(3)

    我们学习了如何定义一个全局的变量 (set, setq), 以及如何定义一个函数. 函数可以有参数, 这个函数的参...

  • [译] Emacs Lisp 速成

    From:http://emacsist.com/10845 点 这里 查看更多 Emacs 相关推荐文章 或 最...

网友评论

    本文标题:谈谈Emacs Lisp的异步

    本文链接:https://www.haomeiwen.com/subject/mzbrjttx.html