Vim 执行异步任务

作者: xOuOx | 来源:发表于2017-03-18 13:10 被阅读215次

    概述

    Vim从8.0版本开始支持异步IO,通过job来开始执行另一个进程,通过channel来进行进程通信。

    只要Vim的版本高于8.0,并且在编译时有+channel+job的feature,就可以通过使用Vim的异步支持来让插件或脚本拥有更好的体验,比如异步编译使Vim在编译时不在阻塞、异步语法高亮来时Vim获得更快的速度等。

    使用

    has('channel')
    has('job')
    

    来判断Vim是否有相关支持。

    我有一个在Vim中翻译单词的插件,但在网络不好的情况下翻译会阻塞正常的浏览,本文是我希望插件可以进行异步翻译而进行的学习笔记,只简单记录了job的工作方式,更多详细内容请在Vim中使用:help channel查看。

    job的工作方式

    job可以理解为Linux中的进程,通过:

    job_start(command, {options})
    

    可以在这个一个进程(job)中执行command,job_start返回job对象,使用

    let channel = job_getchannel(job)
    

    可以获得与job关联的channel用于通信,本文不再讨论。

    command是要执行的外部命令,如果要获取命令的执行结果或状态,可以使用options设置回调函数来完成。

    处理任务输出

    捕获每次输出

    如果command产生输出,可以使用out_cb定义回调函数处理输出:

    func! Handler(channel, msg)
        " deal with msg 
    endfunc
    
    let job = job_start(command, {"out_cb", "Handler"})
    

    cb表示callback

    或者可以使用ch_read(job)或者cd_readraw(job)读取job产生的输出

    捕获结束输出

    如果不想处理任务的中间输出,可以使用close_cb定义回调函数获取结束job的输出:

    func! CloseHandler(channel)
      while ch_status(a:channel, {'part': 'out'}) == 'buffered'
        echomsg ch_read(a:channel)
      endwhile
    endfunc
    
    let job = job_start(command, {'close_cb': 'CloseHandler'})
    
    处理任务的错误输出

    out_cb指定的回调函数不会接收标准错误输出,可以使用err_cb指定的回调函处理错误输出:

    let job = job_start(command, {"out_cb": "Handler",
            \                     "err_cb": "ErrHandler"})
    

    callback指定的回调函数既可以接收错误输出,也可以接收普通输出

    let job = job_start(command, {"callback": "MyHandler"}) 
    

    控制job

    得到job状态:

    job_status(job)
    

    停止job:

    job_stop(job)
    

    示例

    如果我们有一个耗时3s的外部程序要执行,程序执行之后输出日期,如果使用过去的方法,将其映射到<F3>键(这里使用sleep 3s模拟该耗时程序):

    nnoremap <F3> :!/bin/bash -c 'sleep 3s; date'<CR>
    

    点击<F3>后Vim将有3s处于阻塞状态,无法进行任何操作。

    接下来使用异步来处理这个程序:

    " 回调函数
    func! Handler(channel, msg)
        echo a:msg
    endfunc
    
    " 执行job
    func! GetDate()
        call job_start(['/bin/bash', '-c', 'sleep 3s; date'], {'callback': 'Handler'})
    endfunc
    
    nnoremap <F3> :call GetDate()<cr>
    

    此时再点击<F3>,Vim将不会阻塞,可以继续进行操作,并在3s后输出日期。

    相关文章

      网友评论

      • Homer1ynn:你好,我用python的Flask框架,写了一个app的后端程序,想试着执行一下,不知道可行吗?如果执行一个正常的python脚本文件是没有问题的(比如打印'hello world'),执行这个会阻塞,如果可行的话,有什么办法吗?

      本文标题:Vim 执行异步任务

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