Модуль serialport узла не работает с дочерним процессом fork()

Я пытаюсь сделать асинхронное чтение в USB с помощью fork() из модуля child_process в электронном. То есть, когда я нажимаю div (id = "read"), сообщение отправляется от процесса рендеринга основному процессу, который затем в ответ вызывает fork() и асинхронно считывает данные с USB. Для обработки USB-коммуникаций я использую библиотеку node-serialport.

index.html

<html>

    <head>
        <link rel="stylesheet" href="style.css">
        <link rel="stylesheet" href="scroll.css">
        <link href="https://fonts.googleapis.com/css?family=Questrial" rel="stylesheet">
    </head>

    <body>

        <div id="ui-container">


            <div id="top-bar" class="shadowed">
                <div id="top-bar-left-decoration"></div>
                <div id="close-app" class="top-bar-button"><div class="unselectable top-button-text">x</div></div> 
                <div id="maximize-app" class="top-bar-button"><div class="unselectable top-button-text">&#9633</div></div> 
                <div id="minimize-app" class="top-bar-button"><div class="unselectable top-button-text">-</div></div>
            </div>

            <div id="navigation-bar"> 
                <div id="deviceSelection" class ="unselectable navigation-button">

                    <img id="deviceSelection-image" class="navigation-image" src="Icons/selectDevice2.png">
                </div>

                <div id="info" class="unselectable navigation-button">

                    <img id="info-image" class="navigation-image" src="Icons/DeviceInfoNoBorder.png">
                </div>

                <div id="config" class=" unselectable navigation-button">

                    <img id="config-image" class="navigation-image" src="Icons/DeviceConfigNoBorder.png">
                </div>

                <div id="graph" class="unselectable navigation-button">

                    <img id="graph-image" class="navigation-image" src="Icons/DataViewNoBorder.png">
                </div>

                <div id="export" class="unselectable navigation-button">

                    <img id="export-image" class="navigation-image" src="Icons/Export.png">
                </div>

                <div id="options-container"><img id="options" src="Icons/options.png"></div> 

            </div>

            <div id="information-data-view" class="unselectable">
                <div id="data">
                        <div id="push-to-read"></div>
                </div>
            </div>

        </div>


    </body>

    <script src="ipcRenderer.js" type="text/javascript"></script>
</html>

Это мой index.js, отвечающий за создание окна браузера

const electron = require('electron')
const ipcMain = require('electron').ipcMain
const url = require('url')
const path = require('path')
const child_process = require('child_process')
const app = electron.app


var windowFullScreen = false;

const BrowserWindow = electron.BrowserWindow



var MainWindow;
app.on('ready', function()
{
    MainWindow = new BrowserWindow({
        width: 1024, 
        height: 768, 
        backgroundColor : '123355',
        frame: false,
        resizable: true,
        movable: true,
        show: false
    })

MainWindow.on('ready-to-show', () => {
    MainWindow.show()
    console.log('Ready to go!')
})
MainWindow.loadURL(url.format({
    pathname: path.join(__dirname, 'index.html'),
    protocol: 'file:',
    slashes: true
}))
ipcMain.on("minimize", (event, arg) => {
    MainWindow.minimize()
    console.log("minimize")
})
ipcMain.on("maximize", (event, arg) => {
    if (!windowFullScreen) {
        MainWindow.maximize()
        windowFullScreen = true;
    }
    else {
        MainWindow.setSize(800, 600)
        windowFullScreen = false;
    }

    console.log("maximize")
})
ipcMain.on("close", (event, arg) => {
    MainWindow.close()
    console.log("close")
})

ipcMain.on("read", (event, arg) => {
    setInterval(()=>{console.log(usbcomm.read(1))}, 1)
    const process = child_process.fork('./readUSB.js')
})
})

ipcRenderer.js

Здесь я настраивал обработчики событий onclick для DOM. Соответствующей частью здесь является read.onclick(), который отправляет сообщение "read" главному процессу, сообщая ему о том, что он разветвляется и запускает readUSB.js, который я включил ниже.

const electron = require('electron');
const ipcRenderer = electron.ipcRenderer;


var minimize = document.getElementById("minimize-app");
var maximize = document.getElementById("maximize-app");
var read = document.getElementById("push-to-read");
var close = document.getElementById("close-app");

minimize.onclick = (event) => {
    ipcRenderer.send("minimize", "an-argument")
    console.log("minimize");    
} 

maximize.onclick = (event) => {
    ipcRenderer.send("maximize", "an-argument")
    console.log("maximize")
} 

close.onclick = (event) => {
    ipcRenderer.send("close", "an-argument")
    console.log("close")
}

read.onclick = (event) => {
    ipcRenderer.send("read", "an-argument")
    console.log("read")
}

readUSB.js

этот код должен просто прочитать байт с USB и вывести его на консоль, вместо этого он ничего не читает и выдает null (usbcomm.read () возвращает null, если он ничего не читал). Это всего лишь подтверждение концепции, чтобы убедиться, что я могу читать () асинхронно, но, очевидно, что вещи не работают правильно.

const SerialPort = require('serialport')
const usbcomm = new SerialPort("COM4")
usbcomm.setEncoding('utf-8')


usb_rx();


function usb_rx()
{

    console.log("running in child process!")
    console.log(usbcomm.read(1))

}

если я запускаю этот код как обработчик событий в ответ на сообщение "read" от процесса визуализации, все работает нормально, и я читаю правильные ответы от usb. Я подтвердил, что это не проблема с моим USB-устройством, и что в простых случаях использования usbcomm.read () ведет себя так, как ожидалось.

Теперь мне интересно, не будет ли по какой-либо причине узел-последовательный порт работать с кодом, запущенным внутри fork().

1 ответ

Решение

Вы можете сделать блокировку звонков от рендерера. Пока вы держите их ниже 20-30 мс и не забиваете процесс блокировкой вызовов, все будет в порядке. Мы использовали node-serialport а также node-ffi в процессе рендеринга интенсивно выполняются десятки вызовов в секунду, передаются мегабайты данных, при этом пользовательский интерфейс остается отзывчивым без рывков.

Может быть, вы не можете держать блокирующие вызовы достаточно короткими? Как насчет того, чтобы сделать это в основном процессе? Это тоже плохая идея. Блокировка основного процесса блокирует IPC между визуализаторами и процессом GPU, так что вы, вероятно, тоже повесите интерфейс.

Если вам действительно нужно долго блокировать синхронные вызовы, сделайте их в скрытом процессе визуализации. Вы можете заблокировать это столько, сколько хотите, потому что он не отображает никакой пользовательский интерфейс. Чтобы сделать это проще, вы можете использовать electron-remote - renderer-taskpool особенность, чтобы натолкнуть долго выполняющиеся задачи на другой процесс рендеринга.

Другие вопросы по тегам