Node.js и мьютексы
Мне интересно, нужны ли мьютексы/блокировки для доступа к данным в Node.js. Например, скажем, я создал простой сервер. Сервер предоставляет несколько методов протокола для добавления и удаления из внутреннего массива. Нужно ли мне защищать внутренний массив с помощью некоторого типа мьютекса?
Я понимаю, что Javascript (и, следовательно, Node.js) является однопоточным. Я просто не понимаю, как обрабатываются события. Прерывают ли события? Если это так, мое приложение может быть в середине чтения массива, прервать его, чтобы запустить обратный вызов события, который изменяет массив, а затем продолжить обработку массива, который теперь был изменен обратным вызовом события.
Ответы
Ответ 1
Мне интересно, требуются ли мьютексы/блокировки для доступа к данным в Node.js.
Нету! События обрабатываются в тот момент, когда нет другого кода для запуска, это означает, что не будет никаких конфликтов, поскольку только текущий запущенный код имеет доступ к этому внутреннему массиву. Как побочный эффект однопоточного узла, длинные вычисления будут блокировать все остальные события, пока вычисления не будут завершены.
Я понимаю, что Javascript (и, следовательно, Node.js) является однопоточным. Мне просто не ясно, как обрабатываются события. Прерываются ли события?
Нет, события не прерываются. Например, если вы while(true){}
в свой код while(true){}
, это остановит выполнение любого другого кода, потому что всегда есть другая итерация цикла, который нужно запустить.
Если у вас длительные вычисления, рекомендуется использовать process.nextTick, так как это позволит запускать его, когда ничего не запущено (я не совсем уверен в этом: приведенный ниже пример показывает, что я, вероятно, прямо об этом работает бесперебойно, наверное).
Если у вас есть другие вопросы, не стесняйтесь заходить в # node.js и задавать вопросы. Кроме того, я попросил пару человек посмотреть на это и убедиться, что я не совсем неправ;)
var count = 0;
var numIterations = 100;
while(numIterations--) {
process.nextTick(function() {
count = count + 1;
});
}
setTimeout(function() {
console.log(count);
}, 2);
//
//=> 100
//
Благодаря AAA_awright из # node.js :)
Ответ 2
Замки и мьютексы действительно необходимы иногда, даже если Node.js является однопоточным.
Предположим, у вас есть два файла, которые должны иметь один и тот же контент и не иметь одного и того же содержимого, как несогласованное состояние. Теперь предположим, что вам нужно изменить их, не блокируя сервер. Если вы это сделаете:
fs.writeFile('file1', 'content', function (error) {
if (error) {
// ...
} else {
fs.writeFile('file2', 'content', function (error) {
if (error) {
// ...
} else {
// ready to continue
}
});
}
});
вы попадаете в несогласованное состояние между двумя вызовами, когда другая функция в том же script может считывать два файла.
Модуль rwlock идеально подходит для обработки этих случаев.
Ответ 3
Я искал решение для мьютексов node. Иногда необходимы взаимные блокировки - вы можете запускать несколько экземпляров вашего приложения node и, возможно, захотите заверить, что только один из них выполняет какую-то определенную вещь. Все решения, которые я мог найти, были либо не перекрестными, либо зависящими от redis.
Итак, я сделал свое собственное решение, используя блокировки файлов: https://github.com/Perennials/mutex-node
Ответ 4
Мьютексы определенно необходимы для многих реализаций на стороне сервера. Рассмотрим класс, в котором вам необходимо поддерживать синхронность асинхронного выполнения путем построения цепочки обещаний.
let _ = new WeakMap();
class Foobar {
constructor() {
_.set(this, { pc : Promise.resolve() } );
}
doSomething(x) {
return new Promise( (resolve,reject) => {
_.get(this).pc = _.get(this).pc.then( () => {
y = some value gotten asynchronously
resolve(y);
})
})
}
}
Как вы можете быть уверены в том, что обещание не будет зависеть от состояния гонки? Это разочаровывает, что этот узел не сделал мьютексы нативными, поскольку javascript настолько асинхронен по своей природе, и перенос сторонних модулей в пространство процесса всегда представляет угрозу безопасности.