写点什么

Node.js V0.12 新特性之给子进程的同步 API

2014 年 4 月 16 日

尽管发明 Node.js 的初衷主要是为了编写Web 服务器,但开发人员又发现了其他适用(和不适用!)Node 的用途。令人觉得惊喜的是,这些用途中有一个是编写shell 脚本。并且那确实有意义:Node 的跨平台支持已经相当好了,既然前端和后端都用JavaScript 写了,如果构建系统也用JavaScript 写不是更好吗,对吧?

异步对shell 脚本的坏处

在这一用途上值得称道的库是 Grunt ,它是构建在 ShellJS 之上的。然而 ShellJS 有一块硬骨头要啃:Node 迫使它用异步 I/O。尽管对于 Web 服务器来说异步 I/O 很棒,因为它必须随时做出响应,但对于需要逐步执行的 shell 脚本来说,异步 I/O 意义不大。

所以,ShellJS 的作者们发现了一个“有趣的”解决办法,让它可以运行一个 shell 命令,然后等着命令完成。大致上是下面这样的代码:

复制代码
var child_process = require('child_process');
var fs = require('fs');
function execSync(command) {
// 在子 shell 中运行命令
child_process.exec(command + ' 2>&1 1>output && echo done! > done');
// 阻塞事件循环,知道命令执行完
while (!fs.existsSync('done')) {
// 什么都不做
}
// 读取输出
var output = fs.readFileSync('output');
// 删除临时文件。
fs.unlinkSync('output');
fs.unlinkSync('done');
return output;
}

换句话说,在 shell 执行你的命令时,ShellJS 依然在运行,并持续不断地轮询着文件系统,检查是否能找到表明命令已经完成的那个文件。有点儿像驴子

这种效率低下又丑陋不堪的解决办法让 Node 核心团队受刺激了,实现了一个真正的解决方案 – Node v0.12 最终应该会支持同步运行子进程。实际上这个特性已经在路线图上放了很长时间了– 我记得是在2011 年的 JSConf.eu 上 (!) ,跟现在已经退休的 Node 维护者 Felix Geisendoerfer 坐在一起,勾勒出了一个实现 execSync 的办法。在过了两年多以后,这一特性现在终于出现在了 master 分支上

恭喜,ShellJS 的人们挑了一个很好的刺儿! :)

同步对 shell 脚本的好处

我们刚加上的 API spawnSync 跟它的异步小伙伴类似,它提供的底层 API 让你可以完全掌控子进程的设置。它还会返回所有我们能够收集的信息:退出码、终止信号、可能的启动错误,以及这个进程的全部输出。当然,在流中使用 spawnSync 没有任何意义 - 它是同步的,所以事件处理器不能在进程退出前运行 - 所以进程的所有输出会被缓冲到一个单例字符串或缓冲对象中。

并且就像众所周知的 exec(运行 shell 命令)和 execFile(用于运行一个可执行文件) 方法一样,我们为常见的情况添加了 execSync 和 execFileSync,它们比 spawnSync 更易用。如果你用了这些 API,Node 会假定你关心的只是进程写到 stdout 中的数据。如果进程或 shell 返回了非零的退出码,node 会认为出现错误了,exec(Sync) 会抛出。

比如获取项目 git 历史的代码就像下面这样简单:

复制代码
var history = child_process.execSync('git log', { encoding: 'utf8' });
process.stdout.write(history);

现在你可能在想“怎么要用这么长时间?”从表面上看,启动一个子进程并读取它的输出看起来简直是小菜一碟。也确实是这样 - 如果你只关心非常常见的情况。但是,我们不想做出来的解决方案只是一半。

当需要同时发送输入并读取一或多个输出流时,有两个选择:用线程 - 或者用事件循环。比如 Python 的实现,我们发现他们或者用事件循环(在 Unix 系的平台上)或者用线程(在 Windows 上)。并且它的实现可真不是一碟小菜。

2011 年我们就意识到 Node 已经有一个非常棒的事件循环库了,即 libuv 。理论上已经具备了实现这一特性的所有条件。然而总是有或大或小的问题,让它并不能真正可靠地工作。

比如说,当子进程退出时,kernel 会给 node 发送一个 SIGCHLD 信号通知它,但当有多个事件循环存在时,有很长一段时间 libuv 都不能正确处理信号。还有,删除事件循环并且不留下堆栈跟踪的能力也是最近才加上的。之前 Node 根本不管,它只是在某点退出,然后让 OS 打扫战场。如果我们需要一个临时的事件循环,并且在不需要它后仍然继续运行,这种策略就不太合适了。

慢慢的,随着时间的推移,所有这些问题都被解决了。所以如果你现在再设法看看过去那些缓冲区管理、参数解析、超时处理等诸如此类的东西,你会发现这个特性的核心只是一个事件循环,带子进程、计时器,还有一堆附着在它上面的管道。

如果你不关心它都是如何运作的,只需要看看文档,让node 为控制子进程提供的丰富选项震你一下吧。现在谁愿意去把ShellJS 修好?:)

作者简介

本文最初由 Bert Belder 发表在 StrongLoop 上。Bert Belder 从 2010 年就开始做 Node.js 了,并且他还是 libuv 的主要编写者之一,Node.js 就是在这个库上构建的。他除了是 StrongLoop 和 Node 核心的技术领导者,他正在做的特性还会让 Node 处于创新的最前沿,甚至是在 1.0 版出来之后。 StrongLoop 降低了在 Node 中开发APIs 的难度,还添加了监测、集群化以及私有注册的支持等DevOps 能力。

查看英文原文: What’s New in Node.js v0.12 – execSync: a Synchronous API for Child Processes 2014 年 3 月 12 日

2014 年 4 月 16 日 20:284074
用户头像

发布了 45 篇内容, 共 22.3 次阅读, 收获喜欢 3 次。

关注

评论

发布
暂无评论
发现更多内容

《迅雷链精品课》第十二课:PoW共识算法

迅雷链

区块链

Spark-submit执行流程,了解一下

华为云开发者社区

spark 技术 流程

区块链加速产业革命,打造畜禽养殖业发展新途径

CECBC区块链专委会

养殖业

云上的移动性能测试平台

应用研发平台EMAS

阿里云 测试 移动研发平台

我哭了!Centos6停止更新只能切换7,哪些习惯也需要切换

小Q

Java Linux centos 学习 面试

三分钟看懂新一代.Net Core3.1工作流引擎平台

Philips

敏捷开发 工作流

构师训练营第八周学习笔记

李日盛

笔记

LeetCode题解:515. 在每个树行中找最大值,DFS,JavaScript,详细注释

Lee Chen

算法 LeetCode 前端进阶训练营

如何判断一个区块链项目是否优质?

CECBC区块链专委会

开源代码

【得物技术】MySQL多表关联同步到ES的实践

得物技术

MySQL 原理 配置 ES 多表join

最简单的Go Dockerfile编写姿势,没有之一!

Kevin Wan

go Docker Dockerfile

装机必备:借用IDM实现百度云高速下载

懒得勤快

什么是802.11ax(Wi-Fi 6)

网络技术平台

分布式事务框架 seata-golang 通信模型详解

阿里巴巴云原生

go golang 数据库 微服务 云原生

使用LiteOS Studio图形化查看LiteOS在STM32上运行的奥秘

华为云开发者社区

LiteOS 脚本 语言

华为云亮相QCon2020深圳站,带你体会大厂的云原生玩法与秘诀

华为云开发者社区

专家 华为云 深圳

海阔天空的游戏出海,HMS生态提供的风帆与通路

脑极体

腾讯T1~T9级别工程师具备专业的能力及知识点总结。

Linux服务器开发

程序员 腾讯 工程师 Linux服务器开发 岗位级别

让垃圾分类开发“极快致简”的好物件,零基础的开发小白也能轻松驾驭它!

华为云开发者社区

数据 分类

多国探路数字货币

CECBC区块链专委会

数字货币

跨专业零基础校招拿到网易18K*13薪Java岗offer全过程复盘总结

Java架构师迁哥

一周信创舆情观察(11.30~12.6)

统小信uos

Serverless 如何落地?揭秘阿里核心业务大规模落地实现

阿里巴巴云原生

阿里巴巴 阿里云 Serverless 开发者 云原生

架构师训练营第三周课后作业

万有引力

Github上标星82.1K+star面试笔记,可以帮你搞定95%以上的Java面试,已经帮助多人拿下offer

云流

学习 程序员 面试 计算机

开除AI伦理学家,谷歌如何从“不作恶”到“不宽容”?

脑极体

Redis为什么用跳表而不用平衡树?

Java架构师迁哥

Singleton手绘

raox

极客大学架构师训练营

训练营第八周作业

大脸猫

极客大学架构师训练营

github上标星70.5k,贼火的Java突击手册,全面详细对标阿里P7

Crud的程序员

Java 多线程 架构师 java面试 java基础

训练营第八周总结

大脸猫

极客大学架构师训练营

InfoQ 极客传媒开发者生态共创计划线上发布会

InfoQ 极客传媒开发者生态共创计划线上发布会

Node.js V0.12新特性之给子进程的同步API-InfoQ