2014-11-23 2 views
1

Я хотел бы выполнить произвольно поставленную пользователем часть кода javascript в каждой строке файла. Я создал простое приложение командной строки узла, что будет - в качестве примера - просто взять каждую строку и выведет на экран его длина:Производительность динамического javascript node.js

#!/usr/bin/env node 
// eachline.js - execute some js per line in a file 

var fs = require('fs'), 
    readline = require('readline'); 
    vm = require('vm'); 

var args = process.argv.slice(2); 

if (args.length < 1) { 
    console.log("Usage: eachline.js FILENAME") 
    process.exit(code=1) 
} 

var rd = readline.createInterface({ 
    input: fs.createReadStream(args[0]), 
    output: process.stdout, 
    terminal: false 
}); 

var context = vm.createContext({}); 
// this snippet should be user supplied, arbitrary javascript 
var script = vm.createScript('output = input.length'); 

rd.on('line', function(line) { 
    context.input = line; 
    script.runInContext(context); 
    console.log(context.output); 
}); 

Производительность не является оптимальным. Для файла с 1 миллиона строк, это занимает несколько минут:

$ time ./eachline.js 1M.txt > /dev/null 

real 4m14.366s 
user 4m12.200s 
sys  0m4.545s 

С awk эта простая операция занимает около пяти секунд. С similar program, который выполняет произвольный javascript чуть более десяти секунд.

Я раньше не работал с узлом, поэтому вышеприведенная программа является моей первой необразованной догадкой в ​​решении. Как я могу улучшить производительность?

Edit: Выше исходного кода в сущности: https://gist.github.com/miku/31864156938fcd0c8430


PS. Цель состоит в том, чтобы иметь программу, которая может быстро запускать произвольный javascript в каждой строке файла.

+0

Можете ли вы объяснить больше о том, чего вы пытаетесь достичь? Это действительно не ясно из вопроса, как опубликовано. Почему вы хотите запускать код для каждой строки в отдельном контексте? – Pointy

+0

Пользователь должен иметь возможность определить фрагмент js для выполнения на каждой строке динамически. 'vm.runInNewContext' - это метод, который я нашел, который позволил передать некоторый контекст для выполнения (здесь, вход' строка') и из которого я мог бы вернуть результат (здесь, 'output'). – miku

+1

Вы пытались просто создать контекст * один раз * и повторно использовать это для каждой строки? – mscdex

ответ

3

Попробуйте это:

var context = vm.createContext({}); 
// this snippet should be user supplied, arbitrary javascript 
var script = vm.createScript('(function (input) { return input.length; })'); 
var fn = script.runInContext(context); 

rd.on('line', function(line) { 
    console.log(fn(line)); 
}); 

Идея заключается в том, чтобы обернуть при условии выражения в функции, оценить сценарий и затем использовать эту функцию. Я думаю, что v8 не оптимизирует код внутри script, потому что он не должен запускаться более одного раза.

+0

Спасибо, но это похоже на «ReferenceError': https://gist.github.com/miku/31864156938fcd0c8430#file-err-md – miku

+1

вам нужно обернуть код в функцию и передать ввод в качестве аргумента:' ' (function (input) {return input.length;}) '' – vkurchatkin

+0

Извините, я впервые пробовал закрытие. Это действительно дает огромное ускорение, с 4 до 23 лет. – miku

Смежные вопросы