You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity中如何按顺序异步执行带OnComplete回调的DoWork方法?

Unity中顺序异步执行Person.DoWork的解决方案

一、不修改原DoWork方法的原生实现(无.NET Task)

Unity自带的协程(Coroutine)是最适合的方案,完全在主线程运行,无需修改原有DoWork方法,也不会出现冻结问题:

// 顺序执行所有Person的DoWork,靠协程+回调控制流程
public IEnumerator ExecuteAllPersonsWorkSequentially()
{
    foreach (var person in personList)
    {
        bool workCompleted = false;
        // 调用原DoWork,传入回调标记完成状态
        person.DoWork(() => 
        {
            workCompleted = true;
        });
        // 每一帧检查完成状态,不会阻塞主线程
        while (!workCompleted)
        {
            yield return null;
        }
    }
}

// 启动协程的方式(在MonoBehaviour类中调用)
StartCoroutine(ExecuteAllPersonsWorkSequentially());

核心逻辑:用yield return null让协程暂停到下一帧再检查状态,避免了轮询占用CPU的问题,完全贴合Unity的帧循环机制。

二、若改用Task方案(解决你之前的冻结问题)

你之前的代码冻结,本质是用while (!allowExit) { await Task.Yield(); }的轮询方式低效且可能导致主线程调度异常。改用TaskCompletionSource包装回调,彻底摆脱轮询:

修改DoWork方法(兼容主线程)

public Task DoWork()
{
    var taskSource = new TaskCompletionSource<bool>();
    // 利用tool.Start的回调触发Task完成
    tool.Start(() =>
    {
        taskSource.SetResult(true);
    });
    return taskSource.Task;
}

// 顺序执行的调用方法
public async Task RunAllPersonsWork()
{
    foreach (var person in personList)
    {
        // ConfigureAwait(true)确保回到Unity主线程执行后续逻辑
        await person.DoWork().ConfigureAwait(true);
    }
}

// 启动方式(在MonoBehaviour中)
private async void Start()
{
    await RunAllPersonsWork();
}

这种方式没有轮询,只有当tool.Start的回调触发时才会继续执行下一个任务,CPU占用极低,也不会出现冻结。

三、你之前代码冻结的原因

while (!allowExit) { await Task.Yield(); }的轮询方式会频繁将任务重新加入主线程调度队列,即使allowExit被触发,也可能因为调度延迟导致短时间内的CPU占用过高;而协程的yield return null是严格按Unity帧循环暂停,每一帧只检查一次状态,不会出现这类问题。

内容的提问来源于stack exchange,提问作者solidcomer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 06:55:17