Информация об изменениях

Сообщение Re[11]: Для тех, кто смеется над JavaScript от 17.06.2020 9:34

Изменено 17.06.2020 10:43 Pauel

Re[11]: Для тех, кто смеется над JavaScript
Здравствуйте, Sharov, Вы писали:

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>Он однопоточных и асинхронный. Доступ по идее будет сериализуемым.


Это фатальное заблуждение. В ноде никакого серилизуемого доступа, если речь не про блокирующие вызовы. Он однопоточный, но тем не менее многозадачный. Те самые колбеки и тд, это кооперативная многозадачность. То есть, недетерминизм в полный рост. Только гонки надо искать не из за потоков, а из за колбеков и эвентлупа.

Например, операция доступа к ресурсу следующая —
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);
});