From 433ada07ccddeb862527adaff0235c061f9a52ef Mon Sep 17 00:00:00 2001 From: SmallMain Date: Fri, 8 Nov 2024 20:56:06 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=A4=9A=E7=BA=BF=E7=A8=8B?= =?UTF-8?q?=E6=89=A9=E5=B1=95=E7=9A=84=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 14 +- docs/docs/best-practices/performance-guide.md | 12 +- docs/docs/installation/installation-manual.md | 6 + docs/docs/intro.md | 12 +- .../assets/custom_worker_struct.png | Bin 0 -> 30740 bytes .../user-guide/multithread/thread-custom.md | 254 ++++++++++++++++++ .../user-guide/multithread/thread-intro.mdx | 4 +- 7 files changed, 285 insertions(+), 17 deletions(-) create mode 100644 docs/docs/user-guide/multithread/assets/custom_worker_struct.png create mode 100644 docs/docs/user-guide/multithread/thread-custom.md diff --git a/README.md b/README.md index dae7b18d..6714697d 100644 --- a/README.md +++ b/README.md @@ -94,21 +94,23 @@ Label 一直是项目优化的最难点,因为它完全不能和其它的渲 单个 TiledMap 组件可能存在多个 TiledLayer,启用 Culling 特性后,每个 Layer 都需要单独计算 Culling 数据。 -现在在满足条件的情况下可以复用 Culling 数据,以减少项目 CPU 的性能消耗。 +现在在满足条件的情况下可以**复用 Culling 数据,以减少项目 CPU 的性能消耗**。 ### 多线程支持 -现在,以下引擎的部分增加了多线程支持: +**现在,以下引擎的部分增加了多线程支持:** -- 资源管线(下载与缓存部分) -- 音频系统 +- **资源管线(下载与缓存部分)** +- **音频系统** 启用后可以释放其对主线程的占用,减少卡顿现象。 +除此之外,还**支持自定义多线程扩展**,大幅简化了将项目逻辑多线程化所需的步骤! + 并且在微信小游戏平台下还有以下改进: -- 默认启用网络接口和音频接口的高性能模式 -- 网络接口支持 HTTP/2、HTTP/3(QUIC) 协议 +- **默认启用网络接口和音频接口的高性能模式** +- **网络接口支持 HTTP/2、HTTP/3(QUIC) 协议** ## 演示 diff --git a/docs/docs/best-practices/performance-guide.md b/docs/docs/best-practices/performance-guide.md index 751b3c16..79c8120e 100644 --- a/docs/docs/best-practices/performance-guide.md +++ b/docs/docs/best-practices/performance-guide.md @@ -100,16 +100,18 @@ Spine 组件现在不仅可以参与动态合图,还能与其他渲染组件 ## 启用多线程支持 -现在,以下引擎的部分增加了多线程支持: +**现在,以下引擎的部分增加了多线程支持:** -- 资源管线(下载与缓存部分) -- 音频系统 +- **资源管线(下载与缓存部分)** +- **音频系统** 启用后可以释放其对主线程的占用,减少卡顿现象。 +除此之外,还**支持自定义多线程扩展**,大幅简化了将项目逻辑多线程化所需的步骤! + 并且在微信小游戏平台下还有以下改进: -- 默认启用网络接口和音频接口的高性能模式 -- 网络接口支持 HTTP/2、HTTP/3(QUIC) 协议 +- **默认启用网络接口和音频接口的高性能模式** +- **网络接口支持 HTTP/2、HTTP/3(QUIC) 协议** 详情请阅读文档:[多线程支持](../user-guide/multithread/thread-intro)。 diff --git a/docs/docs/installation/installation-manual.md b/docs/docs/installation/installation-manual.md index f5cc5e8a..a2ca93ec 100644 --- a/docs/docs/installation/installation-manual.md +++ b/docs/docs/installation/installation-manual.md @@ -65,6 +65,12 @@ description: "需掌握一定的自定义引擎知识。" 部分代码编辑器可能需要重启之后类型提示才会生效。 +## 更新多线程扩展的 TypeScript 类型提示(可选) + +如果你正在将项目升级到社区版的新版本,并且之前还创建了多线程扩展的话,可以通过依次点击菜单项 **扩展 - 创建新扩展插件... - 项目多线程扩展** 来更新 `creator-worker.d.ts` 文件。 + +关于多线程扩展请阅读文档:[多线程支持](../user-guide/multithread/thread-intro)。 + ## 重启 Cocos Creator 完成以上的步骤后重启 Cocos Creator。 diff --git a/docs/docs/intro.md b/docs/docs/intro.md index cb316ae6..a7a678f8 100644 --- a/docs/docs/intro.md +++ b/docs/docs/intro.md @@ -96,17 +96,19 @@ Label 一直是项目优化的最难点,因为它完全不能和其它的渲 ### 多线程支持 -现在,以下引擎的部分增加了多线程支持: +**现在,以下引擎的部分增加了多线程支持:** -- 资源管线(下载与缓存部分) -- 音频系统 +- **资源管线(下载与缓存部分)** +- **音频系统** 启用后可以释放其对主线程的占用,减少卡顿现象。 +除此之外,还**支持自定义多线程扩展**,大幅简化了将项目逻辑多线程化所需的步骤! + 并且在微信小游戏平台下还有以下改进: -- 默认启用网络接口和音频接口的高性能模式 -- 网络接口支持 HTTP/2、HTTP/3(QUIC) 协议 +- **默认启用网络接口和音频接口的高性能模式** +- **网络接口支持 HTTP/2、HTTP/3(QUIC) 协议** ## 使用方法 diff --git a/docs/docs/user-guide/multithread/assets/custom_worker_struct.png b/docs/docs/user-guide/multithread/assets/custom_worker_struct.png new file mode 100644 index 0000000000000000000000000000000000000000..8de6cb6465b9bbec118f94492400f6741c633fb7 GIT binary patch literal 30740 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 N9W9V%;VtXX{|8 { + console.log('Worker math add result:', v); +}); +``` + +这个函数将在 Worker 线程内执行,而不会阻塞主线程。 + +让我们来编写一个在 Worker 线程中计算斐波那契数列的函数,来深入了解多线程代码的编写! + +## 编写多线程脚本 + +### 创建脚本 + +我们先在 `src` 目录创建一个 `fibonacci.js` 脚本。 + +然后在 `index.js` 添加新的一行来导入它: + +```js +require("fibonacci.js"); +``` + +这样引擎在创建 Worker 时才会执行这个新脚本。 + +### 编写函数 + +在 `fibonacci.js` 脚本中实现计算斐波那契的函数: + +```js +function _fibonacci(n) { + if (n <= 0) return 0; + if (n === 1) return 1; + return fibonacci(n - 1) + fibonacci(n - 2); +} +``` + +### 导出函数到主线程 + +现在,虽然在 Worker 线程中我们有了这个函数,但是我们无法在主线程调用它。 + +与 Worker 线程的通信通常使用 `postMessage` 和 `onMessage` 进行,但是需要处理很多边缘情况,而且这样的开发体验也较差,所以社区版提供了一个封装。 + +我们需要导入 `registerHandler` 函数: + +```js +const { registerHandler } = require("ipc-worker.js"); +``` + +该函数的签名是: + +```ts +export function registerHandler(name: string, handler: object): void; +``` + +调用函数时,函数会执行以下操作: + +- 在全局变量 `worker` 的对象上增加一个与传入 `name` 一样的对象属性。 +- 遍历传入 `handler` 对象上的所有属性,按规则在 `worker.` 对象上创建对应的函数。 + +也就是说,我们只需要将 `fibonacci` 函数传入到 `registerHandler` 函数并调用,函数就可以在主线程中调用了! + +以下是完整的 `fibonacci.js` 内容: + +```js +const { registerHandler } = require("ipc-worker.js"); + +function _fibonacci(n) { + if (n <= 0) return 0; + if (n === 1) return 1; + return fibonacci(n - 1) + fibonacci(n - 2); +} + +function fibonacci(n, callback) { + callback(_fibonacci(n)); +} + +registerHandler("utils", { + fibonacci, +}); +``` + +### 导出的内部原理 + +你可能注意到了我们导出的是另一个函数,而不是直接导出 `_fibonacci` 函数。 + +因为这是实现一个跨线程调用函数时需要遵循的规范: + +- 与 `postMessage` 的要求一样,函数的所有参数必须是可序列化的。 +- 当函数被调用时,会在函数最后一个参数传入一个回调函数,当需要返回到主线程时,请调用该函数。 + +像上面 `fibonacci` 函数的实现,在调用 `_fibonacci` 拿到计算结果后,通过调用 `callback(v)` 将值返回到主线程。 + +而在主线程中,我们需要像这样从主线程调用 Worker 线程中的这个函数: + +```js +worker.utils.fibonacci([10], ([v]) => { + console.log('Worker fibonacci result:', v); +}); +``` + +你可能注意到了,第一个参数是数组,而第二个参数的回调的第一个参数也是数组,这也是规范。 + +为了提高跨线程通信的性能,减少垃圾回收的频率,所以选择了这种调用的方式。 + +你可以这样理解 `worker.xxx.xxx()` 的调用签名: + +``` +worker.utils.fibonacci(args, (values) => ...); + +// utils: 要调用的 handler 名称 +// fibonacci: 要调用 handler 中的 Worker 函数名称 +// args: 传入到 Worker 函数的所有参数 +// values: Worker 函数返回时的回调,参数是返回值数组 +``` + +这很好理解,我们再举个多参数调用的例子: + +```js +// Worker 线程的函数 +function handle(a, b, c, callback) { + // a = "ye.", b = {}, c = 1000 + callback(1, "text", { prop: 2 }); +} + +// 主线程的调用方式 +worker.utils.handle(["ye.", {}, 1000], ([v1, v2, v3]) => { + // v1 = 1, v2 = "text", v3 = { prop: 2 } +}); +``` + +### 更多导出场景 + +无参数函数的实现与调用: + +```js +// Worker 线程的函数 +function setValue(callback) { + // ... + callback(); +} + +// 主线程的调用方式 +worker.utils.setValue(() => { + // ok. +}); +``` + +无需返回的函数的实现与调用(这同时能节省 Worker 的通信开销,因为只需要单向通信!): + +```js +// Worker 线程的函数 +function setValue(v) { + // ... + // 执行完成之后不调用 callback,甚至不用声明 +} + +// 主线程的调用方式 +worker.utils.setValue(["ye."]); +``` + +无参数也无返回的函数的实现与调用(这同时能节省 Worker 的通信开销,因为只需要单向通信!): + +```js +// Worker 线程的函数 +function setValue() { + // ... + // 执行完成之后不调用 callback,甚至不用声明 +} + +// 主线程的调用方式 +worker.utils.setValue(); +``` + +除了函数之外,你还可以导出值、getter/setter 属性,但需要注意需通过 `get_xxx`、`set_xxx` 和 `write_xxx` 三个代理函数进行访问与修改: + +```js +// Worker 线程中: + +registerHandler("Date", { + time: 1, +}); + +// 主线程中: + +// 获取值 +worker.Date.get_time(([v]) => { + // v is 1. +}); + +// 修改值,不会回调,性能比 write 更高 +worker.Date.set_time([100]); + +// 修改值,会回调以通知操作已执行完毕 +worker.Date.write_time([100], () => { + // finish. +}); +``` + +## 编译多线程扩展 + +每次修改扩展代码之后,需要手动点击 **项目 - 重新编译多线程扩展** 以生效。 + +特别注意:**就像修改多线程的设置会影响到所有项目一样,多线程扩展的编译结果也是所有项目共用的!** + +所以当你**构建某个项目之前,必须确保最后一次编译是当前项目的多线程扩展**! diff --git a/docs/docs/user-guide/multithread/thread-intro.mdx b/docs/docs/user-guide/multithread/thread-intro.mdx index 01741b43..063bfb83 100644 --- a/docs/docs/user-guide/multithread/thread-intro.mdx +++ b/docs/docs/user-guide/multithread/thread-intro.mdx @@ -5,7 +5,7 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common'; :::caution 注意 -以下所有多线程特性暂时仅适用于微信小游戏平台。 +本章节所有多线程特性暂时仅适用于微信小游戏平台。 并且在微信小游戏平台下还有以下改进: @@ -27,6 +27,8 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common'; - CC_WORKER_ASSET_PIPELINE(是否启用 Worker 驱动资源管线) - CC_WORKER_AUDIO_SYSTEM(是否启用 Worker 驱动音频系统) - CC_WORKER_DEBUG(是否启用 Worker 调试模式) +- CC_CUSTOM_WORKER(是否启用自定义 Worker) +- CC_WORKER_AUDIO_SYSTEM_SYNC_INTERVAL(Worker 音频系统同步音频属性的间隔时间(单位:毫秒)) 例如这样: