Сообщение Re[11]: Для тех, кто смеется над JavaScript от 17.06.2020 9:34
Изменено 17.06.2020 10:43 Pauel
Re[11]: Для тех, кто смеется над JavaScript
Здравствуйте, Sharov, Вы писали:
H>>Это интересно. А как там с многопоточностью, в движке ноды? Как разграничивается доступ к общему ресурсу из нескольких потоков?
S>Он однопоточных и асинхронный. Доступ по идее будет сериализуемым.
Это фатальное заблуждение. В ноде никакого серилизуемого доступа, если речь не про блокирующие вызовы. Он однопоточный, но тем не менее многозадачный. Те самые колбеки и тд, это кооперативная многозадачность. То есть, недетерминизм в полный рост. Только гонки надо искать не из за потоков, а из за колбеков и эвентлупа.
Например, операция доступа к ресурсу следующая —
В итоге, ресурс хранит данные всех шагов некоторого вычисления и в хидере указаны соответствующие ссылки.
Теперь представим, что будет, если сделаем, скажем, вот такую хрень
То есть, мы здесь запустили 6 параллельных цепочек, каждая из которых работает с одним и тем же разделяемым ресурсом.
Вопрос — что будет в конце? А будет хаос, содержимое файла скорее всего будет представлять непойми что — одна цепочка обновила хидер, этот хидер тут же перезаписывается другой цепочкой. Она цепочка сделала запись в конец, но по этому же смещению тут же пишет другая цепочки.
А если вот так:
Вот это сериализуемый доступ, и сделано это руками. То есть, такую гарантию, как сериализуемый доступ, в ноде приходится делать руками. И так с любым разделяемым ресурсом.
H>>Это интересно. А как там с многопоточностью, в движке ноды? Как разграничивается доступ к общему ресурсу из нескольких потоков?
S>Он однопоточных и асинхронный. Доступ по идее будет сериализуемым.
Это фатальное заблуждение. В ноде никакого серилизуемого доступа, если речь не про блокирующие вызовы. Он однопоточный, но тем не менее многозадачный. Те самые колбеки и тд, это кооперативная многозадачность. То есть, недетерминизм в полный рост. Только гонки надо искать не из за потоков, а из за колбеков и эвентлупа.
Например, операция доступа к ресурсу следующая —
async update(path, pattern) {
const resource = await open(path); // доступ к ресурсу разделяемый, а не эксклюзивный !!!
const oldHeader = await readHeader(resource);
const {newPattern, newHeader} = await nextStep(pattern, oldHeader);
await writeToEnd(resource, newPattern);
await updateHeader(resource, newHeader);
await close(resource);
}
В итоге, ресурс хранит данные всех шагов некоторого вычисления и в хидере указаны соответствующие ссылки.
Теперь представим, что будет, если сделаем, скажем, вот такую хрень
update(path, pattern1);
update(path, pattern2);
update(path, pattern3);
update(path, pattern4);
update(path, pattern5);
update(path, pattern6);
То есть, мы здесь запустили 6 параллельных цепочек, каждая из которых работает с одним и тем же разделяемым ресурсом.
Вопрос — что будет в конце? А будет хаос, содержимое файла скорее всего будет представлять непойми что — одна цепочка обновила хидер, этот хидер тут же перезаписывается другой цепочкой. Она цепочка сделала запись в конец, но по этому же смещению тут же пишет другая цепочки.
А если вот так:
await update(path, pattern1);
await update(path, pattern2);
await update(path, pattern3);
await update(path, pattern4);
await update(path, pattern5);
await update(path, pattern6);
Вот это сериализуемый доступ, и сделано это руками. То есть, такую гарантию, как сериализуемый доступ, в ноде приходится делать руками. И так с любым разделяемым ресурсом.
Re[11]: Для тех, кто смеется над JavaScript
Здравствуйте, Sharov, Вы писали:
H>>Это интересно. А как там с многопоточностью, в движке ноды? Как разграничивается доступ к общему ресурсу из нескольких потоков?
S>Он однопоточных и асинхронный. Доступ по идее будет сериализуемым.
Это фатальное заблуждение. В ноде никакого серилизуемого доступа, если речь не про блокирующие вызовы. Он однопоточный, но тем не менее многозадачный. Те самые колбеки и тд, это кооперативная многозадачность. То есть, недетерминизм в полный рост. Только гонки надо искать не из за потоков, а из за колбеков и эвентлупа.
Например, операция доступа к ресурсу следующая —
В итоге, ресурс хранит данные всех шагов некоторого вычисления и в хидере указаны соответствующие ссылки.
Теперь представим, что будет, если сделаем, скажем, вот такую хрень
То есть, мы здесь запустили 6 параллельных цепочек, каждая из которых работает с одним и тем же разделяемым ресурсом.
Вопрос — что будет в конце? А будет хаос, содержимое файла скорее всего будет представлять непойми что — одна цепочка обновила хидер, этот хидер тут же перезаписывается другой цепочкой. Она цепочка сделала запись в конец, но по этому же смещению тут же пишет другая цепочки.
А если вот так:
Вот это сериализуемый доступ, и сделано это руками. То есть, такую гарантию, как сериализуемый доступ, в ноде приходится делать руками. И так с любым разделяемым ресурсом.
Реально вот такое чудо не встречается, что бы все опреации сами по себе шли подряд, нужно пилить чтото более приемлемое. Например, соорудить нечто навроде мутекса или семафора:
H>>Это интересно. А как там с многопоточностью, в движке ноды? Как разграничивается доступ к общему ресурсу из нескольких потоков?
S>Он однопоточных и асинхронный. Доступ по идее будет сериализуемым.
Это фатальное заблуждение. В ноде никакого серилизуемого доступа, если речь не про блокирующие вызовы. Он однопоточный, но тем не менее многозадачный. Те самые колбеки и тд, это кооперативная многозадачность. То есть, недетерминизм в полный рост. Только гонки надо искать не из за потоков, а из за колбеков и эвентлупа.
Например, операция доступа к ресурсу следующая —
async update(path, pattern) {
const resource = await open(path); // доступ к ресурсу разделяемый, а не эксклюзивный !!!
const oldHeader = await readHeader(resource);
const {newPattern, newHeader} = await nextStep(pattern, oldHeader);
await writeToEnd(resource, newPattern);
await updateHeader(resource, newHeader);
await close(resource);
}
В итоге, ресурс хранит данные всех шагов некоторого вычисления и в хидере указаны соответствующие ссылки.
Теперь представим, что будет, если сделаем, скажем, вот такую хрень
update(path, pattern1);
update(path, pattern2);
update(path, pattern3);
update(path, pattern4);
update(path, pattern5);
update(path, pattern6);
То есть, мы здесь запустили 6 параллельных цепочек, каждая из которых работает с одним и тем же разделяемым ресурсом.
Вопрос — что будет в конце? А будет хаос, содержимое файла скорее всего будет представлять непойми что — одна цепочка обновила хидер, этот хидер тут же перезаписывается другой цепочкой. Она цепочка сделала запись в конец, но по этому же смещению тут же пишет другая цепочки.
А если вот так:
await update(path, pattern1);
await update(path, pattern2);
await update(path, pattern3);
await update(path, pattern4);
await update(path, pattern5);
await update(path, pattern6);
Вот это сериализуемый доступ, и сделано это руками. То есть, такую гарантию, как сериализуемый доступ, в ноде приходится делать руками. И так с любым разделяемым ресурсом.
Реально вот такое чудо не встречается, что бы все опреации сами по себе шли подряд, нужно пилить чтото более приемлемое. Например, соорудить нечто навроде мутекса или семафора:
const mutex = queue(path, 1); // 1 - количество читателей-писателей которым разрешено одновременно работать с ресурсом
// http хандлер
app.post(async (req, res) => {
const {path, pattern} = resolveArgs(req);
await mutex(() => update(path, pattern)); // все запросы автоматически становятся в очередь
res.send('', 204);
});