NODEJS: метод Uncork() в записываемом потоке на самом деле не сбрасывает данные
Я пишу довольно простое приложение для преобразования данных - читать один файл и писать в другой. Файлы относительно большие - 2 Гб. Однако то, что я обнаружил, это то, что сброс в файловую систему не происходит, в цикле cork-uncork он происходит только при end(), поэтому end () в основном подвешивает систему, пока она полностью не мигнет. Я упростил пример, поэтому он много раз просто записывает строку в поток.
var PREFIX = 'E:\\TEST\\';
var line = 'AA 11 999999999 20160101 123456 20160101 AAA 00 00 00 0 0 0 2 2 0 0 20160101 0 00';
var fileSystem = require('fs');
function writeStrings() {
var stringsCount = 0;
var stream = fileSystem.createWriteStream(PREFIX +'output.txt');
stream.once('drain', function () {
console.log("drained");
});
stream.once('open', function (fileDescriptor) {
var started = false;
console.log('writing file ');
stream.cork();
for (i = 0; i < 2000000; i++) {
stream.write(line + i);
if (i % 10000 == 0) {
// console.log('passed ',i);
}
if (i % 100000 == 0) {
console.log('uncorcked ',i,stream._writableState.writing);
stream.uncork();
stream.cork();
}
}
stream.end();
});
stream.once('finish', function () {
console.log("done");
});
}
writeStrings();
Зайдя в узел _stream_writable.js, я обнаружил, что он очищает буфер только при следующем условии:
if (!state.writing &&
!state.corked &&
!state.finished &&
!state.bufferProcessing &&
state.buffer.length)
clearBuffer(this, state);
и, как вы можете видеть из примера, флаг записи не устанавливается обратно после первой uncork(), что предотвращает сброс uncork. Кроме того, я не вижу вызывающих утечку событий вообще. Игра с highWaterMark не помогает (фактически ни на что не влияет). Ручная установка записи в false (+ некоторые другие флаги) действительно помогла, но это, безусловно, неправильно. Я неправильно понимаю концепцию этого?
2 ответа
Из документации по node.js я обнаружил, что число uncork() должно соответствовать номеру вызова cork (), я не вижу соответствующего вызова stream.uncork() для stream.cork(), который вызывается перед циклом for. Это может быть проблемой.
Глядя на руководство на nodejs.org, вы не должны звонить stream.uncork()
дважды в одном и том же цикле событий. Вот выдержка:
// Using .uncork() twice here makes two calls on the C++ layer, rendering the
// cork/uncork technique useless.
ws.cork();
ws.write('hello ');
ws.write('world ');
ws.uncork();
ws.cork();
ws.write('from ');
ws.write('Matteo');
ws.uncork();
// The correct way to write this is to utilize process.nextTick(), which fires
// on the next event loop.
ws.cork();
ws.write('hello ');
ws.write('world ');
process.nextTick(doUncork, ws);
ws.cork();
ws.write('from ');
ws.write('Matteo');
process.nextTick(doUncork, ws);
// as a global function
function doUncork(stream) {
stream.uncork();
}
.cork()
можно вызывать столько раз, сколько мы хотим, нам просто нужно быть осторожным, чтобы позвонить .uncork()
такое же количество раз, чтобы заставить его течь снова.