前言
nodejs从第十版开始,支持了真正的多线程编程,今天我们就来学习一下worker_threads工作线程的一些基本使用方法。
主线程与工作线程
我们做一个特别简单的例子,主线程给工作线程提供参数,工作线程负责简单的加法计算(实际场景可以是很复杂的计算),计算完毕返回给主线程。
运行主线程即可得到执行结果。
主线程(main.js
)
- 引入工作线程构造函数
Worker
传入work.js
的文件地址创建工作线程work
。 - 工作线程
work
可以通过postMessage
传递数据,这里传递了一个对象过去。 - 工作线程
work
可以通过监听message
方法获得工作线程传来的数据。
import {Worker} from 'worker_threads'
const work = new Worker('./work.js')
work.postMessage({x: 1, y: 2})
work.on('message', value => {
console.log(value)
})
工作线程(work.js
)
- 引入
parentPort
可以与主线程(引入了该工作线程的线程)进行交互。 parentPort.onmessage
方法可以获取主线程传来的数据,与work.postMessage
相对应,传来的数据在event.data
中,event
还有一些其他参数。parentPort.postMessage
方法可以传递数据去主线程,与work
的监听message
方法相对应
import {parentPort} from 'worker_threads'
const getSum = (x, y) => {
return x + y
}
parentPort.onmessage = (event) => {
const {x, y} = event.data
const res = getSum(x, y)
parentPort.postMessage(res)
}
工作线程交互
假如我们需要两个工作线程之间进行交互,需要依赖主线程搭建桥梁。
至于搭建桥梁的工具,则是依赖中的MessageChannel
,它可以提供两个可以互相传递数据的端口。
下面的例子简单演示了端口1向端口2传递数据,一个传递数据一个接收数据。
反之也一样的,端口2向端口1传递数据也是同样的方法。
import {MessageChannel} from 'worker_threads'
const {port1, port2} = new MessageChannel()
port1.postMessage('123')
port2.onmessage = ev => {
console.log(ev.data)
}
那我们怎么利用MessageChannel
来进行工作线程间的交互呢?
只要分别将两个端口传去对应的工作线程不就好了吗?
- 传递端口不可以简单的使用
postMessage
的第一个数据入参传递,只能通过第二个参数并且以数组的形式传递。 - 我们在传送对象数据中加入参数
type
,type
为port
用告诉工作线程我们传递的是端口,需要进行端口的监听操作。 - 同时我们传递
type
为send
的数据,负责端口的发送数据操作。 - 两边既有监听又有发送,即实现了通信。
主线程(main.js
)
import {Worker, MessageChannel} from 'worker_threads'
let work1 = new Worker('./work1.js')
let work2 = new Worker('./work2.js')
const {port1, port2} = new MessageChannel()
work1.postMessage({type: 'port'}, [port1])
work2.postMessage({type: 'port'}, [port2])
work1.postMessage({type: 'send', value: '从线程1向线程2传递信息'})
work2.postMessage({type: 'send', value: '从线程2向线程1传递信息'})
工作线程1(work1.js
)
- 从主线程传来的
port
可以通过event.ports[0]
得到,我们在工作线程1创建好port1
的监听事件,随时可以接收到port2
传来的数据。 - 同时我们在额外创建一个
send
类型事件,就可以在主线程,控制两个工作线程之间传递消息了。
import {parentPort} from 'worker_threads'
let port1
parentPort.onmessage = (event) => {
const {type, value} = event.data
switch (type) {
case 'port':
port1 = event.ports[0]
port1.onmessage = ev => {
console.log(ev.data)
}
break
case 'send':
port1.postMessage(value)
break
default:
break
}
}
工作线程2(work2.js
)
与工作线程1同理。
import {parentPort} from "worker_threads";
let port2
parentPort.onmessage = (event) => {
const {type, value} = event.data
switch (type) {
case 'port':
port2 = event.ports[0]
port2.onmessage = ev => {
console.log(ev.data)
}
break
case 'send':
port2.postMessage(value)
break
default:
break
}
}
尾言
内容并不多,主要是nodejs中需要用到工作线程的实际可用场景并不多,将来若有机会还会继续补充。
如果有任何错误或者建议,欢迎指出,我会及时修改。
如果文章对你有帮助的话,欢迎点赞收藏~