节点串口模块不与子进程 fork() 一起工作
node serialport module not working with child process fork()
我正在尝试使用电子中 child_process 模块的 fork() 在 usb 中进行异步读取。也就是说,当我点击 div (id="read") 时,一条消息从渲染进程发送到主进程,然后作为响应调用 fork() 并从 USB 读取数据异步地。为了处理 USB 通信,我使用 node-serialport library。
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">□</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,负责创建浏览器window
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
这是我为 DOM 设置 onclick 事件处理程序的地方。这里的相关部分是 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() returns 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() 的行为符合预期。
我现在想知道 node-serialport 是否出于某种原因不能与 fork() 内部的代码 运行 一起使用。
您可以从渲染器进行阻塞调用。只要您将它们保持在 20-30 毫秒以下,并且您不会因阻塞调用而淹没该过程,您就可以了。我们在渲染器进程中广泛使用了 node-serialport
和 node-ffi
,每秒进行数十次调用,传输数兆字节的数据,同时保持 UI 响应没有抖动。
也许您不能将阻塞调用保持得足够短?在主进程中如何做?这也是一个坏主意。阻塞主进程会阻塞渲染器和 GPU 进程之间的 IPC,因此您也可能会以这种方式挂起 UI。
如果您确实需要进行长时间阻塞的同步调用,请在隐藏的渲染器进程中进行调用。您可以随意屏蔽它,因为它不会显示任何 UI。为了使这更容易,您可以使用 electron-remote - renderer-taskpool
功能将长 运行 任务转移到另一个渲染器进程。
我正在尝试使用电子中 child_process 模块的 fork() 在 usb 中进行异步读取。也就是说,当我点击 div (id="read") 时,一条消息从渲染进程发送到主进程,然后作为响应调用 fork() 并从 USB 读取数据异步地。为了处理 USB 通信,我使用 node-serialport library。
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">□</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,负责创建浏览器window
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
这是我为 DOM 设置 onclick 事件处理程序的地方。这里的相关部分是 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() returns 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() 的行为符合预期。
我现在想知道 node-serialport 是否出于某种原因不能与 fork() 内部的代码 运行 一起使用。
您可以从渲染器进行阻塞调用。只要您将它们保持在 20-30 毫秒以下,并且您不会因阻塞调用而淹没该过程,您就可以了。我们在渲染器进程中广泛使用了 node-serialport
和 node-ffi
,每秒进行数十次调用,传输数兆字节的数据,同时保持 UI 响应没有抖动。
也许您不能将阻塞调用保持得足够短?在主进程中如何做?这也是一个坏主意。阻塞主进程会阻塞渲染器和 GPU 进程之间的 IPC,因此您也可能会以这种方式挂起 UI。
如果您确实需要进行长时间阻塞的同步调用,请在隐藏的渲染器进程中进行调用。您可以随意屏蔽它,因为它不会显示任何 UI。为了使这更容易,您可以使用 electron-remote - renderer-taskpool
功能将长 运行 任务转移到另一个渲染器进程。