Unity进阶篇:主线程和子线程概念及注意点

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_15020543/article/details/83956945

先理解一下什么是线程:

线程是操作系统级别的概念,现代操作系统都实现并且支持线程,线程的调度对应用开发者是透明的,开发者无法预期某线程在何时被调度执行。基于此,一般那种随机出现的BUG,多与线程调度相关。

什么是Unity主线程?

通俗点讲,Unity的主流程生命周期函数就是主线程

常用的生命周期函数:

Awake():唤醒事件,游戏一开始运行就执行,只执行一次。

OnEnable():启用事件,只执行一次。当脚本组件被启用的时候执行一次。

Start():开始事件,执行一次。

FixedUpdate():固定更新事件,执行N次,0.02秒执行一次。所有物理组件相关的更新都在这个事件中处理。

Update():更新事件,执行N次,每帧执行一次。

LateUpdate():稍后更新事件,执行N次,在 Update() 事件执行完毕后再执行。

OnGUI():GUI渲染事件,执行N次,执行的次数是 Update() 事件的两倍。

OnDisable():禁用事件,执行一次。在 OnDestroy() 事件前执行。或者当该脚本组件被“禁用”后,也会触发该事件。

OnDestroy():销毁事件,执行一次。当脚本所挂载的游戏物体被销毁时执行。

扫描二维码关注公众号,回复: 4023227 查看本文章

那么什么是子线程呢?(不在主线程运行的程序都叫子线程)

我的理解,最直接的是new Thread()一个线程

using System.Collections;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;

public class NewBehaviourScript : MonoBehaviour {
    private Thread T;

    void Start () 
    {
        T = new Thread(ThreadTest);
        T.Start();
	}
	
	void ThreadTest()
    {
        for(int i = 0; i < 3; i++)
        {
            Debug.Log("子线程运行了");
        }
    }
}

还有就是编写网络通信时的回调函数也是子线程。

    /// <summary>
    /// 响应服务器,为回调函数
    /// </summary>
    /// <param name="data"></param>
    public override void OnResponse(string data)
    {
        Debug.Log(data);
    }

多线程一般在什么情况下使用呢?

大量耗时的数据计算

网络请求

复杂密集的I/O(文件写入读取)操作

为什么要使用多线程?

上面那三种情况,如果放到主线程,一般情况下都会卡的不要不要的,所以就需要子线程来分担工作压力

注意点:

  1. 协程不是子线程,对与Unity,它是单线程的设计,它更倾向使用time slicing(时间分片)的协程(coroutine)去完成异步任务,融合到了Unity生命周期中。

    协程Coroutine是编译器级的,本质还是一个线程时间分片去执行代码段。它通过**相关的代码使得代码段能够实现分段式的执行,显式调用yield函数后才被挂起,重新开始的地方是yield关键字指定的,一次一定会跑到一个yield对应的地方。因为协程本质上还是在主线程里执行的,需要内部有一个类似栈的数据结构,当该coroutine被挂起时要保存该coroutine的数据现场以便恢复执行。

    在Unity3D中,协程是可自行停止运行 (yield),直到给定的 YieldInstruction 结束再继续运行的函数。 协程 (Coroutines) 的不同用途:

    • yield; 在下一帧上调用所有 Update 函数后,协同程序将继续运行。

    • yield WaitForSeconds(2); 在指定的时间延迟之后,为此帧调用所有 Update 函数之后继续运行

    • yield WaitForFixedUpdate(); 在所有脚本上调用所有 FixedUpdate 后继续运行

    • yield WWW 完成 WWW 下载后继续运行。

    • yield StartCoroutine(MyFunc); 连接协同程序,并等待 MyFunc coroutine 首先结束。

    也就是说,将代码段分散在不同的帧中,每次执行一段,下一帧再执行yield挂起的地方。

  2. Unity是单线程设计的游戏引擎,子线程中无法运行UnitySDK

    例如,在子线程生成游戏物体(go已在外部添加引用)

    using System.Collections;
    using System.Collections.Generic;
    using System.Threading;
    using UnityEngine;
    
    public class NewBehaviourScript : MonoBehaviour {
        private Thread T;
        public GameObject go;
        void Start () {
            T = new Thread(ThreadTest);
            T.Start();
    	}
    	
    	void ThreadTest()
        {
            for(int i = 0; i < 3; i++)
            {
                Instantiate(go);
                Debug.Log("子线程运行了");
            }
    
        }
    }

    运行就会Internal_CloneSingle can only be called from the main thread.

         在网络回调函数里生成游戏物体也会报同样的错误  

本文可能略有不足,还请大家不吝赐教!

参考

猜你喜欢

转载自blog.csdn.net/qq_15020543/article/details/83956945