#javascript #node.js
#javascript #node.js
Вопрос:
Есть ли способ синхронно отправлять сообщение в другой worker_thread? В этом сценарии
а) принимающий поток будет выполнять асинхронные сетевые операции и не должен быть заблокирован
б) отправляющий поток должен быть заблокирован до тех пор, пока не получит ответ от получателя
Это должна быть синхронная функция для совместимости со сторонней библиотекой. Но возвращаемое значение функции вычисляется из асинхронных сетевых операций, которые я переместил в другой поток.
Я планирую использовать SharedArrayBuffer
и Atomics.wait
в отправляющем потоке для ожидания ответа. Это имеет смысл, потому что отправитель должен быть заблокирован.
Однако, если я использую SharedArrayBuffer
вместо postMessage
отправки сообщения, то принимающий поток должен использовать setImmediate
цикл опроса, а не ждать MessagePort
события message. Я бы предпочел не использовать Atomics.wait
в принимающем потоке, потому что в идеале он имеет разблокированный цикл событий для текущих асинхронных операций. При необходимости я буду использовать опрос или блокировку, но в идеале я могу найти альтернативу.
Комментарии:
1. Нет. Вы не можете заблокировать основной поток, ожидающий ответа от рабочего потока. Цикл событий должен быть запущен, чтобы вы могли получить ответ от рабочего потока (потому что он поступает через цикл событий). Я бы посоветовал вам опубликовать реальную проблему здесь, чтобы мы могли помочь вам разобраться с реальной проблемой, а не только с вашей попыткой решения.
2. Почему бы не использовать
postMessage
для отправки запроса иwait
для принятия ответа?3. @jfriend00 Я могу заблокировать основной поток, ожидающий ответа, с помощью Atomics.wait. Ответ записывается в SharedArrayBuffer, затем worker_thread использует Atomics.notify для пробуждения основного потока. Этот вопрос на самом деле относится к синхронной отправке сообщения в рабочий поток, не ожидая ответа.
4. @Bergi
postMessage
фактически не отправляет сообщение в рабочий поток до тех пор, пока цикл событий отправителя не сможет зациклиться. Я надеюсь, что есть синхронный вызов, который я могу выполнить, чтобы вручную очистить очередь postMessage.5. Не существует «хорошего» способа выполнить асинхронную операцию в node.js быть синхронным. Существуют хаки блокировки, которые включают
child_process.execSync()
и некоторые вещи, которые вы можете сделать в надстройке машинного кода, но это все. Вы не хотите, чтобы казалось, что вы хотите это услышать, но так оно и есть. На моем месте я бы либо нашел другую стороннюю библиотеку, которая может соответствующим образом взаимодействовать с асинхронной операцией, либо изменил бы для этого существующую стороннюю библиотеку.
Ответ №1:
Оказывается, то, чего я хочу достичь, может быть выполнено полностью синхронно, и с postMessage
помощью.
Вместо того, чтобы использовать стандартный, MessagePort
созданный с помощью worker, я создаю свой собственный MessageChannel
и передаю один из портов worker при его запуске. Это необходимо, потому что позже нам понадобится ссылка на порт основного потока.
Запустите порты вручную с помощью .start()
.
Когда рабочему устройству нужно ответить основному потоку, вызовите .postMessage()
для отправки сообщения, затем используйте Atomics.notify()
для пробуждения основного потока. 4-байтового SharedArrayBuffer
достаточно, поскольку мы не передаем никаких данных через SharedArrayBuffer
; он используется только для пробуждения основного потока.
В основном потоке используйте Atomics.wait()
для ожидания уведомления, затем receiveMessageOnPort
для синхронного извлечения сообщения из порта. (вот почему нам нужна ссылка на порт основного потока, упомянутый выше)
Комментарии:
1. Есть ли какая-либо документация по этому поводу или вы выяснили это только экспериментальным путем?
2. Оказывается, все это можно сделать синхронно. Когда у меня будет время, я обновлю ответ. Я думаю, вам просто нужно .start() порты вручную. В документах вроде как говорится об этом, но не явно.
Ответ №2:
Я знаю, что это старый пост, но я смог сделать это с помощью ключевых слов async / await с postMessage и onMessage, обернутых в обещание.
Вот несколько примеров машинописного текста.
public async SendSynchronous(name:Message, value: any)
{
if(GetElapsedTimeInMS != null)
value.time = GetElapsedTimeInMS();
value.sendAck = true;
let messageData: MessageData = {
message: name,
value: value
}
let sendCommand = async () =>
{
return new Promise((resolve,reject) =>
{
this.mPort.onmessage = ({data}) =>
{
this.mPort.onmessage = (ev) => { this.HandleMessage(ev); }
if (!data.value.result.cmdResult)
{
reject(data.error);
}
else
{
if(data.value.result.ReturnValue != null)
resolve(data.value.result.ReturnValue);
else
resolve(true);
}
}
this.SendAsynchronous(name, value);
});
};
//let t = performance.now();
//console.log("calling " name);
let result: any = await sendCommand();
//let d = performance.now() - t;
//console.log("SendSynchronous " d);
this.mCurrentSyncCount = 0;
return resu<
Комментарии:
1.
async
await
однако не является синхронным.