64 lines
3.3 KiB
Markdown
64 lines
3.3 KiB
Markdown
# 线程与异步模块
|
||
|
||
**脚本入口:** `eve.Thread()`
|
||
|
||
使用线程池执行原生安全任务,通过 Channel/Event 把结果送回主线程。
|
||
|
||
## 基本用法
|
||
|
||
```squirrel
|
||
local threads = eve.Thread();
|
||
local channel = threads.newChannel();
|
||
local pool = threads.newThreadPool(2);
|
||
pool.submitPush(channel, "done", 100);
|
||
```
|
||
|
||
## 对象关系与调用时机
|
||
|
||
`Thread` 创建 ThreadPool 与 Channel;Pool 返回 Task;Channel 是 worker 到主线程的字符串通道。脚本 VM 和绝大多数引擎对象只允许主线程访问。
|
||
|
||
## 目标导向指南
|
||
|
||
### 把耗时任务移出主线程
|
||
|
||
创建线程池和 Channel,用 `submitSleep` / `submitPush` / `submitPost` 提交受支持任务;主线程轮询 Channel 或 Event 获取结果。worker 不得访问 Squirrel VM、窗口或 GPU 对象。
|
||
|
||
### 等待关卡加载任务
|
||
|
||
需要观察状态时为每项任务保留 Task,轮询 `isDone()` / `hasFailed()`,显示进度。脚本提前释放 Task 或匿名 Channel 不会中止已提交工作;线程池会持有任务完成所需的原生状态。仅在退出或确定不会卡住界面时调用 `wait()` / `waitAll()`。
|
||
|
||
`newThreadPool(0)` 使用硬件并发度;显式线程数上限为 256。`waitAll()` 与 `stop()` 不能从同一个线程池的 worker 中调用,这类调用会立即抛出异常,避免自等待死锁。
|
||
|
||
## 常见问题
|
||
|
||
- worker 调用 gfx/ui/Squirrel:这些对象不是线程安全的。
|
||
- worker 调用所属 Pool 的 `waitAll()` / `stop()`:会抛出异常;把关闭与汇合操作放在主线程。
|
||
- 主线程立即 `waitAll()`:异步退化成卡顿的同步。
|
||
- 忽略 `hasFailed()` / `getError()`:失败任务会悄悄丢结果。
|
||
- 并发任务使用相同 Event 名称:业务监听仍按队列消费;`asyncPost()` 的 Promise 按具体 Task 关联,不会因同名事件乱序而串线。
|
||
|
||
## API 快查
|
||
|
||
下列方法名来自当前 Squirrel 绑定;同一模块创建的辅助对象(例如 `World`、`Body`、`Source`)的方法也列在这里。
|
||
|
||
- `clear()`、`demand()`、`getChannel()`、`getCount()`、`getError()`、`getHardwareConcurrency()`、`getName()`、`getPendingCount()`
|
||
- `getPool()`、`getStatus()`、`getWorkerCount()`、`hasData()`、`hasFailed()`、`isDone()`、`isRunning()`、`newChannel()`
|
||
- `newThreadPool()`、`pop()`、`postMain()`、`push()`、`stop()`、`submitPost()`、`submitPush()`、`submitSleep()`
|
||
- `supply()`、`wait()`、`waitAll()`
|
||
|
||
## 使用要点
|
||
|
||
- 模块对象和它创建的资源对象应保存在全局或实体状态中,不要在每帧重复创建。
|
||
- 带 `update(dt)` 的系统应在 `eve_update` 调用;绘制方法应在 `eve_render` 调用。
|
||
- 参数约束、默认值和返回类型以对应模块头文件及 `addFunc` 绑定为准;本文 API 快查与当前源码同步生成。
|
||
|
||
**源码:** [`src/modules/thread/`](../../../src/modules/thread/)
|
||
**相关测试:** 在 [`test/`](../../../test/) 中搜索 `thread`。
|
||
|
||
## 资源解码并发
|
||
|
||
ResourceManager 使用的 IAsyncWorkExecutor 拥有独立资源池,工作线程数为
|
||
`min(8, max(1, hardwareConcurrency))`,限制大型解码的并发内存及 CPU 争用。
|
||
普通 `getPool()` 和显式创建的池不受此限制。thread 销毁时先撤销执行器提供者,再等待
|
||
资源任务完成;任务不能在工作线程创建模块或操作图形/脚本状态。
|