Синхронно отправить сообщение в worker_thread. Поток отправки заблокирован, worker_thread разблокирован

#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 однако не является синхронным.