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() такое же количество раз, чтобы заставить его течь снова.

Другие вопросы по тегам