# worker任务
# 简要介绍
在小游戏框架的worker框架中,想要编写在worker中运行的代码,只能通过worker任务的形式。
在编写完worker任务后,任务由小游戏框架自动调度,每帧会执行一次,并在帧末与主线程进行数据交换。
# worker任务类
所有worker任务都需要继承Job
类。
# ▌Job基类的属性和方法
成员 | 类型 | 注释 |
---|---|---|
data | object | 引擎内创建的交互数据块 |
init | abstract ( ) => void | 初始化,worker内创建任务时调用 |
update | abstract ( ) => void | 在update里实现每帧的真实工作; 可通过访问this.data来获取交互数据块 |
onDispose | abstract ( ) => void | 任务中止时的回调。 |
自己实现任务类的时候,只要实现以上四个成员就行了:
import { Job } from "engine-worker-env";
class MyJob extends Job {
public data: object;
public init() {
...
}
public update() {
// real work
}
public onDispose() {
...
}
}
# worker任务的文件位置
worker任务只能放置于worker文件夹下。
如果还未创建worker文件夹,可以在工具内右键某个文件夹,选择设置为worker文件夹
。创建完毕之后,请勿更改自动生成的文件。
worker任务的路径定义为,worker任务类相对于worker文件夹的路径(去除后缀名)。
假如worker文件夹的路径为
游戏根目录/assets/worker/
,worker任务的绝对路径为游戏根目录/assets/worker/jobs/MyJob.ts
。那么MyJob的路径为
jobs/MyJob
。可以用该路径来创建worker任务。
# worker任务的环境
worker任务里的代码只能访问worker文件夹下的内容,并且和游戏主线程是两个互相独立的js环境。
也就是说:
- 不能访问游戏主线程的环境,拿不到
engine
、game
等全局变量,也拿不到任何资源; - 不能
import
worker文件夹外的脚本; - 不能使用worker文件夹外的npm包(要用的话只能在worker文件夹下再npm install一个)。
所以在worker环境里不能访问游戏内的内容。想要访问的话,只能通过帧末和主线程交换数据,让主线程把数据序列化填在共享内存中。
# 交互数据块
在创建worker任务时,需要传入一个用于交互的数据块(jsObject)。
这个数据块在发到至worker的过程中,会经历序列化和反序列化的过程,所以主线程和worker持有的数据块并不是同一份,而是数据的深拷贝。
所以两边想要进行数据交换,只能通过共享内存的方式。小游戏框架内做了工作,来确保共享内存对象在发送至worker后,和主线程访问的仍是同一份内存。
// 创建共享内存并发送
const sab = game.workerSystem.createSharedArrayBuffer(32);
const data = {
buffer: sab
};
const job = game.workerSystem.createJob("jobs/MyJob", data);
// 修改共享内存数据
const view = new Uint8Array(sab.buffer);
view[0] = 1;
# worker任务的状态
worker任务内部是一个状态机,大致流程为:
在主线程创建任务并启动之后,worker环境可能会在1~3帧之后才收到,所以主线程内的任务回调可能会空跑几帧。关于worker有没有进行第一次任务,可以通过worker任务的状态来判断,如果状态为running,则说明至少在worker里跑了一帧了。
# 注意事项
由于每个job拥有单独的通信开销,所以尽量不要建太多job。