shelljs performance is slow

2.6k views Asked by At

I have been using shelljs

On my super fast system I execute this:

var shell = require('shelljs')
const exec = require('child_process').exec

console.time('shell mktemp -d')
shell.exec('mktemp -d', {silent: true})
console.timeEnd('shell mktemp -d')

console.time('child exec mktemp -d')
exec('mktemp', ['-d'], function(error, stdout, stderr) {
  if (error) {
    console.error('stderr', stderr)
    throw error
  }
  console.log('exec stdout', stdout)
  console.timeEnd('child exec mktemp -d')
})

Its giving the following execution times:

shell mktemp -d: 208.126ms

exec stdout /tmp/tmp.w22tyS5Uyu

child exec mktemp -d: 48.812ms

Why is shelljs 4 times slower? Any thoughts?

2

There are 2 answers

0
Théophile Pace On BEST ANSWER

Have a look to how shelljs is implemented: enter image description here

It fully relies on node.js fs library. This library is cross platform and written in C++ but not as performant as C language. More generally, you can't have in JS the perfs you get in C...

Another thing, abstraction layers: you're using exec(Command) where Command is a C tailored (Linux C here I think). The machine creates a thread and executes a command in it. When using shell.js, there are many mechanisms to ensure cross plateform and keep the abstraction of your command as a function and keep the result as a variable. See the code of exec in shell.js: https://github.com/shelljs/shelljs/blob/master/src/exec.js It is not really doing the same thing as your line of code.

Hope that helps!

0
nfischer On

Your code example compares async child_process.exec() with sync shell.exec(), which isn't entirely a fair comparison. I think you'll find shell.exec(..., { async: true }) performs a bit better: this is because sync shell.exec() does extra work to provide real-time stdio while still capturing stdout/stderr/return code as part of its return value; async shell.exec() can provide the same feature mostly for free.

Even with { silent: true }, the extra work is still necessary. shell.exec() is built on top of child_process.execSync(), which only returns stdout. We need to perform the same extra work in order to return return code and stderr.