Unity中C#的协程(迭代器)

1.协程的定义:协同程序,在主线程运行的同时,开启另外一段逻辑处理,来协同当前主线程的执行。协程不是多线程!!!
下面来看例子中的详细解释:从打印结果来分析协同和主线程的关系!!!!

void Start()
    {
        Debug.Log("  001");
        this.StartCoroutine("Test01");
        Debug.Log("  002");
    }
    IEnumerator Test01()
    {
        float timeNum = 0f;
        Debug.Log(" time=" + Time.time);
        yield return new WaitForSeconds(2);
        Debug.Log(" time=" + Time.time);
        for (int i = 0; i < 10; i++)
        {            
            Debug.Log(" time=" + Time.time + "   i=" + i);
            yield return i;
        }
        // 等待物理更新完毕(所有脚本中的FixedUpdate()函数都被执行后从当前位置继续执行)
        yield return new WaitForFixedUpdate();
        // 等待渲染帧完毕(在所有的渲染以及GUI程序执行完成后从当前位置继续执行)
        yield return new WaitForEndOfFrame();
        // 等待一帧 在fixedupdate后执行
        yield return null;
    }

在这里插入图片描述
打印结果顺序:001 -> time=0 -> 002 .
在time=0后面执行 yield return new WaitForSeconds(2); 此时就把执行逻辑交还给主线程了所以才会先打印 002 ,协程中等待2秒后在执行 打印 time=…

2.协程的使用和暂停
StartCoroutine(“方法名”) 或者 StopCoroutine(methodName)
StartCoroutine(“Test01”); StopCoroutine(Test01())
下面详细来说一下协程背后的:迭代器在这里插入图片描述
在这里插入图片描述

    void Test02() {

        List<string> st = new List<string>();
        st.Add("a");
        st.Add("b");
        st.Add("c");
        st.Add("d");
        st.Add("e");
        st.Add("f");
        Debug.Log("----分界线----方法(2)和 方法(1)效果相等--");
        // 方法(2)和 方法(1)效果相等
        // 方法(1)
        var ie = st.GetEnumerator();
        while (ie.MoveNext())
        {
            var cur = ie.Current;
            Debug.Log(" cur ="+ cur);

        }
        //方法(2)
        foreach (var item in st)
        {
            Debug.Log(" cur =" + item);
        }
        ///-----------------------------------------
        
        Debug.Log("----分界线----方法(3)和 方法(4)效果相等--");
        // 方法(3)和 方法(4)效果相等
        // 方法(3)
        foreach (var item in test03())
        {
            Debug.Log("cur = " + item);
        }
        // 方法(4)
        IEnumerator ieTest03 = test03().GetEnumerator();
        while (ie.MoveNext())
        {
            var cur = ieTest03.Current;
            Debug.Log(" cur =" + cur);
        }
    }

    IEnumerable<string> test03()
    {
        for (int i = 0; i < 10; i++)
        {
            yield return i.ToString();
        }
        yield return "";
    }

反编译后查看:

[CompilerGenerated]  
        private sealed class <Power>d__0 : IEnumerable<int>, IEnumerable, IEnumerator<int>, IEnumerator, IDisposable  
        {  
            private int <>1__state;  
            private int <>2__current;  
            public int <>3__exponent;  
            public int <>3__number;  
            public string <>3__s;  
            private int <>l__initialThreadId;  
            public int <i>5__2;  
            public int <result>5__1;  
            public int exponent;  
            public int number;  
            public string s;  

            [DebuggerHidden]  
            public <Power>d__0(int <>1__state)  
            {  
                this.<>1__state = <>1__state;  
                this.<>l__initialThreadId = Environment.CurrentManagedThreadId;  
            }  

            private bool MoveNext()  
            {  
                switch (this.<>1__state)  
                {  
                    case 0:  
                        this.<>1__state = -1;  
                        this.<result>5__1 = 1;  
                        if (string.IsNullOrEmpty(this.s))  
                        {  
                            Console.WriteLine("Begin to invoke GetItems() method");  
                        }  
                        this.<i>5__2 = 0;  
                        while (this.<i>5__2 < this.exponent)  
                        {  
                            this.<result>5__1 *= this.number;  
                            this.<>2__current = this.<result>5__1;  
                            this.<>1__state = 1;  
                            return true;  
                        Label_009D:  
                            this.<>1__state = -1;  
                            this.<i>5__2++;  
                        }  
                        this.<>2__current = 3;  
                        this.<>1__state = 2;  
                        return true;  

                    case 1:  
                        goto Label_009D;  

                    case 2:  
                        this.<>1__state = -1;  
                        this.<>2__current = 4;  
                        this.<>1__state = 3;  
                        return true;  

                    case 3:  
                        this.<>1__state = -1;  
                        this.<>2__current = 5;  
                        this.<>1__state = 4;  
                        return true;  

                    case 4:  
                        this.<>1__state = -1;  
                        break;  
                }  
                return false;  
            }  

            [DebuggerHidden]  
            IEnumerator<int> IEnumerable<int>.GetEnumerator()  
            {  
                Program.<Power>d__0 d__;  
                if ((Environment.CurrentManagedThreadId == this.<>l__initialThreadId) && (this.<>1__state == -2))  
                {  
                    this.<>1__state = 0;  
                    d__ = this;  
                }  
                else  
                {  
                    d__ = new Program.<Power>d__0(0);  
                }  
                d__.number = this.<>3__number;  
                d__.exponent = this.<>3__exponent;  
                d__.s = this.<>3__s;  
                return d__;  
            }  

            [DebuggerHidden]  
            IEnumerator IEnumerable.GetEnumerator()  
            {  
                return this.System.Collections.Generic.IEnumerable<System.Int32>.GetEnumerator();  
            }  

            [DebuggerHidden]  
            void IEnumerator.Reset()  
            {  
                throw new NotSupportedException();  
            }  

            void IDisposable.Dispose()  
            {  
            }  

            int IEnumerator<int>.Current  
            {  
                [DebuggerHidden]  
                get  
                {  
                    return this.<>2__current;  
                }  
            }  

            object IEnumerator.Current  
            {  
                [DebuggerHidden]  
                get  
                {  
                    return this.<>2__current;  
                }  
            }  
        }  

反编译的代码就不详细讲了,下面用一个例子来说明***状态的切换***:

(1)在调用一个使用了迭代器块,返回类型为一个 IEnumerable 或者 IEnumerable接口的方法时,这个方法并非立刻执行我们自己写的代码

(2)而是先创建一个编译器生成的类的实例,然后调用MoveNext方法时(如果返回值是IEnumerable 则要先调用GetEnumerator),我们的代码才开始执行,直到遇到第一个yield return 或 yield break语句,此时返回一个bool值来判断迭代是否结束

(3)当下次再调用MoveNext方法时,我们的方法会继续从上一个yield return语句处开始执行。

测试代码如下:

 void Test04()
    {
        Debug.Log("---调用TestStateChange ");
        IEnumerable<int>iteratorable =  TestStateChange();
        Debug.Log("---调用GetEnumerator ");
        IEnumerator<int> iterator = iteratorable.GetEnumerator();
        Debug.Log("---调用MoveNext ");
        
        bool hasNext = iterator.MoveNext();
        Debug.Log($" 是否有数据 = {hasNext},current={iterator.Current}");
        Debug.Log("第二次调用 moveNext");
        hasNext = iterator.MoveNext();
        Debug.Log($" 是否有数据 = {hasNext},current={iterator.Current}");
        Debug.Log("第三次调用 moveNext");
        hasNext = iterator.MoveNext();
        Debug.Log($" 是否有数据 = {hasNext}");
    }
    IEnumerable<int> TestStateChange()
    {
        Debug.Log("---我TestStateChange 是第一行代码 ");
        Debug.Log("---我是第一个yield return 前的代码 ");
        yield return 1;
        Debug.Log("---我是第一个yield return 后的代码 ");

        Debug.Log("---我是第二个yield return 前的代码 ");
        yield return 2;
        Debug.Log("---我是第二个yield return 后的代码 ");
    }

在这里插入图片描述
通过以上结果,可以清晰的看到 movenext 和 yield return,以及状态时如何切换的:
第一次moveNext发生再GetEnumerator方法之后,此时的状态就已经发生了改变。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值