跳转至

后台工作协调器

这一页说明 GFBackgroundWorkUtility 如何执行纯数据 CPU/IO 线程任务、合并资源线程加载,并把结果安排回主线程应用。

后台工作协调器 (GFBackgroundWorkUtility / GFBackgroundWorkTask)

GFBackgroundWorkUtility 适合真正需要线程执行的“纯数据工作”:解析大型 JSON、生成寻路网格中间数据、压缩/解压缓存、计算导入报告,或把 Godot 的 threaded ResourceLoader 请求纳入统一状态面板。它和 GFJobQueueUtility 的分工不同:任务队列只保存状态并等待项目消费;后台工作协调器会启动受限数量的 Thread,轮询资源线程加载,并把结果安排回下一次 tick() 的主线程应用回调。

var background := Gf.get_utility(GFBackgroundWorkUtility) as GFBackgroundWorkUtility

background.submit_cpu_work(
    func(input: Variant) -> Dictionary:
        var rows := input as Array
        return {
            "count": rows.size(),
            "checksum": hash(rows),
        },
    rows_from_disk,
    func(task: GFBackgroundWorkTask) -> void:
        # 这里已经回到主线程,可以写入 Model、创建节点或刷新 UI。
        print(task.result)
)

默认情况下,submit_cpu_work()submit_io_work() 会拒绝包含 ObjectResourceCallableSignalRID 的 payload,只接受标量、数学结构、PackedArray、Array 和 Dictionary 组成的纯 Variant 数据。这个限制是故意的:线程中不直接触碰场景树、Resource 实例或托管对象,才能避免把 Unity JobSystem 中“绕过托管类型检查却丢掉优化价值”的问题搬进 Godot。确实需要迁移旧代码时可以用 options["allow_object_payloads"] = true 或全局 allow_object_payloads 打开,但推荐做法仍是只传路径、ID、数值和结构化数据。

资源加载使用 submit_resource_load(path, type_hint, apply_callback)。相同路径、兼容 type_hint 的请求会合并到同一个 threaded ResourceLoader 请求;取消只阻止 GF 侧应用和完成回调,不会强行中止 Godot 已经发起的加载线程。CPU/IO 线程任务也是协作式取消:等待中的任务会立刻进入 cancelled,运行中的任务会等 worker 返回后再落到取消终态。get_debug_snapshot() 会报告等待、运行、资源请求、应用队列和终态任务 ID,适合和运行时诊断面板或加载界面联动。

主线程应用回调用 max_apply_per_tick 限制每帧数量;如果每个应用回调成本差异很大,可以再设置 max_apply_seconds_per_tick 作为时间预算。时间预算小于等于 0.0 时关闭;启用后每次 tick() 仍至少尝试一个应用回调,避免预算过低导致队列永远不前进。重活仍应放在线程 worker 中完成,apply_callback 只做写回 Model、创建节点或刷新 UI 这类必须回到主线程的收尾。

这套工具不替代 GFAssetUtilityGFSceneUtility 的专用缓存/切场景能力。需要资源句柄、分组预加载和 LRU 缓存时继续用 GFAssetUtility;需要场景切换和 loading scene 时继续用 GFSceneUtility;需要“排队后由项目自己的系统逐帧消费”时继续用 GFJobQueueUtilityGFBackgroundWorkUtility 的定位是把通用 CPU/IO 纯数据工作和主线程应用边界标准化。