协程协程(迭代器)和WaitWhile的秘密

协程协程(迭代器)和WaitWhile的秘密

1.协程

协程其实就是一个IEnumerator(迭代器),

IEnumerator 接口有两个方法 Current 和 MoveNext()

Unity在每一帧做的事情是:调用协程(迭代器)MoveNext()方法,如果返回true,则从当前位置继续执行。

什么是协程?

协同程序,即在主程序运行时,同时启动另一段逻辑处理,以协同当前程序的执行。也就是说,启动一个协程就是启动一个线程。

协程是部分执行。当遇到条件(yield return语句)时3D角色,会被挂起,直到满足条件后才会被唤醒,继续执行后面的代码。通俗地说:程序可以在里面中断unity 协程和线程区别,然后转而去执行其他的子程序,在合适的时候再返回继续执行。

协程的运行

协程不是线程,也不是异步执行的。协程也像MonoBehaviour的Update函数一样在MainThread中执行。

协程可以与主程序并行运行,类似于多线程。

协程的作用

1.延迟(等待)一段时间执行代码;

2. 在执行以下代码之前等待操作完成。

一句话概括就是:控制代码在特定的时间执行。

go协程和线程区别_go协程和线程的区别_unity 协程和线程区别

粘贴图片.png

WaitForSeconds()受Time.timeScale的影响,当Time.timeScale = 0f时,yield return new WaitForSecond(x)不会被满足。

练习测试

    void Start () {
        print("开始下载" + "---" + Time.time);
        StartCoroutine(waitOne());
        print("正在下载----50%" + "---" + Time.time);
    }
    IEnumerator waitOne()
    {
        Debug.Log("加入下载列表" + "---" + Time.time);
        yield return StartCoroutine(waitTwo());
        print("下载完成" + "---" + Time.time);
    }
    IEnumerator waitTwo()
    {
        print("正在下载----1%" + "---" + Time.time);
        yield return new WaitForSeconds(3);
        print("正在下载----70%" + "---" + Time.time);
    }

打印结果(执行顺序):

go协程和线程区别_unity 协程和线程区别_go协程和线程的区别

粘贴图片.png

脚本协程禁用后还会执行吗?

unity 协程和线程区别_go协程和线程区别_go协程和线程的区别

粘贴图片.png

2.WaitUntil和WaitWhile的秘密

开始学习 WaitUntil:

θ 根据定义,它暂停语句直到指定的条件返回 true。

θ 换句话说,当我们指定的条件为假时,它不会继续执行语句。Unity 将等待条件返回真。

测试

 public int counter;
    void Start ()
    {
        counter = 0;
        StartCoroutine(FuelNotification());
    }
    IEnumerator FuelNotification()
    {
        Debug.Log("开始通关" + "---" + Time.time);
        yield return new WaitUntil(IsTankEmpty);
        Debug.Log("通关了!" + "---" + Time.time);
    }
    void Update()
    {
        if (counter<21)
        {
            Debug.Log("通关数量:"+counter+"---"+Time.time);
            counter++;
        }
    }
    public bool IsTankEmpty()
    {
        if (counter<21)
        {
            return false;
        }
        else
        {
            return true;
        }
    }

打印结果:

go协程和线程的区别_go协程和线程区别_unity 协程和线程区别

粘贴图片.png

让我们来看看如何使用 Lambda 表达式。Lambda 表达式是一个非常方便的工具,试试吧。

 public int counter;
    void Start()
    {
        counter = 20;
        StartCoroutine(FuelNotification());
    }
    void Update()
    {
        if (counter > 0)
        {
            Debug.Log("Fuel Level:" + counter + "---" + Time.time);
            counter--;
        }
    }
    IEnumerator FuelNotification()
    {
        Debug.Log("Waiting for tank to get empty" + "---" + Time.time);
        yield return new WaitUntil(() => counter <= 0);
        Debug.Log("Tank Empty!" + "---" + Time.time);
    }

打印结果:

go协程和线程的区别_unity 协程和线程区别_go协程和线程区别

粘贴图片.png

现在了解 WaitWhile:WaitWhile 与 WaitUntil 相反。当条件为真时,它会抑制表达式。与 WaitUntil 不同的是,它会等到条件变为 false 之后再指向后面的代码块。和之前一样的例子,我们使用了WaitWhile:我们只需要将Lambda表达式改为equal False,打印出来的结果是一样的。

    public int counter;
    void Start()
    {
        counter = 20;
        StartCoroutine(FuelNotification());
    }
    void Update()
    {
        if (counter > 0)
        {
            Debug.Log("Fuel Level:" + counter + "---" + Time.time);
            counter--;
        }
    }
    IEnumerator FuelNotification()
    {
        Debug.Log("Waiting for tank to get empty" + "---" + Time.time);
        yield return new WaitUntil(() => counter > 0);
        Debug.Log("Tank Empty!" + "---" + Time.time);
    }

图片.png

3.线程和协程的区别

线

线程间共享变量解决了通信麻烦的问题,但是变量的访问需要锁,线程的调度主要由操作系统来完成。一个进程可以有多个线程,但是每个线程都会共享父进程来操作系统申请的资源,包括虚拟内存、文件等,由于是共享资源unity 协程和线程区别,所以创建一个线程需要的系统资源要小很多相比进程,相应的可以创建的线程数也变得比较大。除了进程间的通信,线程时的通信还可以通过共享内存进行通信,所以这个速度比通过内核要快很多。另外在调度方面,因为内存是共享的,

协程

协程的调度完全由用户控制。一个线程可以有多个协程。用户创建若干个线程音效,然后每个线程按照指定的任务列表顺序循环完成不同的任务,当任务被阻塞时执行。当下一个任务恢复时,回来执行这个任务。任务之间的切换只需要保存每个任务的上下文内容,就像直接操作栈一样,这样完全没有内核切换的开销,也不需要锁。访问全局变量,所以上下文切换非常快;另外,协程需要保证是非阻塞的,没有相互依赖。协程基本不能同步通信,多使用一步的消息通信,效率更高。