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

如何解决Unity中用户自定义脚本引发主线程阻塞的问题?

解决Unity自定义Update逻辑阻塞主线程的方案

要让游戏对象的逻辑看起来像在独立线程执行,核心是避免在主线程的Update/固定Update里执行长时间阻塞的同步任务,以下是几种落地方案:

1. 用协程拆分任务(最易上手)

协程不是真的多线程,但能把长任务拆分成多帧执行,让主线程有时间处理渲染、输入等工作,看起来像“并行”。
比如原来的阻塞循环:

void Update() {
    // 这个循环会卡住主线程
    for(int i = 0; i < 100000; i++) {
        HeavyCalculation(i);
    }
}

改成协程版本,每帧执行一部分:

IEnumerator ProcessTaskCoroutine() {
    for(int i = 0; i < 100000; i++) {
        HeavyCalculation(i);
        // 让出主线程,下一帧再继续执行
        yield return null;
        // 也可以用yield return new WaitForEndOfFrame(),等当前帧渲染完再继续
    }
}

// 在合适的时机启动协程,比如Awake/Start
void Start() {
    StartCoroutine(ProcessTaskCoroutine());
}

如果想让任务执行得更快,也可以控制每帧执行的迭代次数,比如每帧跑1000次:

IEnumerator ProcessTaskCoroutine() {
    int total = 100000;
    int step = 1000;
    for(int i = 0; i < total; i += step) {
        for(int j = i; j < Mathf.Min(i + step, total); j++) {
            HeavyCalculation(j);
        }
        yield return null;
    }
}

2. 用Unity Job System + Burst(真正多线程)

如果是纯计算密集型任务(不涉及Unity对象的读写),可以用Unity官方的Job System开启子线程执行,完成后再同步回主线程更新游戏对象状态。
示例:

using Unity.Collections;
using Unity.Jobs;
using UnityEngine;

public class JobExample : MonoBehaviour {
    private NativeArray<float> results;
    private JobHandle jobHandle;

    void Start() {
        // 创建Native容器存储计算结果(子线程安全)
        results = new NativeArray<float>(100000, Allocator.Persistent);
        // 创建并调度Job
        var calculationJob = new HeavyCalculationJob {
            Results = results
        };
        jobHandle = calculationJob.Schedule(results.Length, 64);
    }

    void Update() {
        // 检查Job是否完成
        if(jobHandle.IsCompleted) {
            // 等待Job完成并释放资源
            jobHandle.Complete();
            // 在主线程用计算结果更新游戏对象
            for(int i = 0; i < results.Length; i++) {
                // 比如更新某个数组里的对象状态
                // objectList[i].].SetValue(results[i]);
            }
            results.Dispose();
            // 可以在这里停止后续Update检查
            enabled = false;
        }
    }

    // 定义Job
    private struct HeavyCalculationJob : IJobParallelFor {
        public NativeArray<float> Results;

        public void Execute(int index) {
            // 这里是纯计算,不能调用Unity的API(比如Transform、GameObject)
            Results[index] = Mathf.Sin(index * 0.1f) * Mathf.Cos(index * 0.05f);
        }
    }
}

注意:Job里绝对不能直接访问Unity的MonoBehaviour、Transform等对象,必须通过NativeContainer传递数据,且要注意内存管理(用完必须Dispose)。

3. 手动拆分任务到多帧

如果不想用协程或Job System,也可以手动记录任务进度,每帧执行一小段:

private int currentIteration = 0;
private const int totalIterations = 100000;
private const int iterationsPerFrame = 500;

void Update() {
    int end = Mathf.Min(currentIteration + iterationsPerFrame, totalIterations);
    for(int i = currentIteration; i < end; i++) {
        HeavyCalculation(i);
    }
    currentIteration = end;
    // 任务完成后停止执行
    if(currentIteration >= totalIterations) {
        enabled = false;
    }
}

关键注意事项

  • 所有涉及Unity游戏对象的操作(比如修改Transform位置、调用Renderer方法)必须在主线程执行,子线程只能处理纯计算逻辑。
  • 如果需要在子线程执行任务后更新UI或游戏对象,可自己实现一个主线程调度器,把回调抛回主线程执行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 16:45:44