理解Unity中的协程的使用

今天,换项目组以后,不用lable,想用下自己定制的数字,发现居然没人写。

那就把旧项目的东西拿过来,看了看源码,注意到了协程这货,而且最近同事也鼓励我们试试用协程,于是就来研究一下吧。

查了一些文档,以下是整理和总结:

本文实例讲述了C#中yield return用法,并且对比了使用yield return与不使用yield return的情况,以便读者更好的进行理解。具体如下

本篇文章转载于:http://www.jb51.net/article/54810.htm 

yield关键字用于遍历循环中,yield return用于返回IEnumerable<T>,yield break用于终止循环遍历。

有这样的一个int类型的集合:

static List<int> GetInitialData()
{
    return new List<int>() { 1, 2, 3, 4 };
}

需要打印出所有值大于2的元素。

不使用yield return的实现

static IEnumerable<int> FilterWithoutYield()
{
    List<int> result = new List<int>();
    foreach (int i in GetInitialData())
    {
        if (i > 2)
        {
            result.Add(i);
        }
    }
    return result;
}


客户端调用:

static void Main(string[] args)
{
    foreach (var item in FilterWithoutYield())
    {
        Console.WriteLine(item);
    }
    Console.ReadKey();
}

输出结果:3,4

使用yeild return实现

static IEnumerable<int> FilterWithYield()
{
    foreach (int i in GetInitialData())
    {
        if (i > 2)
        {
            yield return i;
        }
    }
    yield break;
    Console.WriteLine("这里的代码不执行");
}

客户端调用:

static void Main(string[] args)
{
    foreach (var item in FilterWithYield())
    {
        Console.WriteLine(item);
    }
    Console.ReadKey();
}

输出结果:3,4

总结:

通过单步调试发现:

虽然2种方法的输出结果是一样的,但运作过程迥然不同。第一种方法,是把结果集全部加载到内存中再遍历;第二种方法,客户端每调用一次,yield return就返回一个值给客户端,是"按需供给"。

第一种方法,客户端调用过程大致为:

使用yield return,客户端调用过程大致为:

使用yield return为什么能保证每次循环遍历的时候从前一次停止的地方开始执行呢?

--因为,编译器会生成一个状态机来维护迭代器的状态。

简单地说,当希望获取一个IEnumerable<T>类型的集合,而不想把数据一次性加载到内存,就可以考虑使用yield return实现"按需供给"

文转载于http://www.jb51.net/article/54810.htm  


那么好了,理解了yield return之后,就来体验一下在u3d中是如何使用协程的吧:


StartCoroutine在unity3d的帮助中叫做协程,意思就是启动一个辅助的线程。

本篇文章转载于 http://www.cnblogs.com/xpvincent/archive/2013/07/13/3188257.html 感谢作者:马语者

在C#中直接有Thread这个线程,但是在unity中有些元素是不能操作的。这个时候可以使用协程来完成。

使用线程的好处就是不会出现界面卡死的情况,如果有一次非常大量的运算,没用线程就会出现假死的情况。

下面通过一个简单的例子来说明使用协程的好处: 

void OnGUI()  
    {  
        GUI.Label(new Rect(0, 0, 200, 50), "测试1:" + result);  
        if (GUI.Button(new Rect(0, 100, 100, 50), "开启协程"))  
        {  
            StartCoroutine(GetResult());  
        }  
  
        GUI.Label(new Rect(200, 0, 200, 50), "测试2:" + result1);  
        if (GUI.Button(new Rect(200, 100, 100, 50), "无协程测试"))  
        {  
            GetResult1();  
        }  
    }  


上面的代码表示在GUI中定义2个label和按钮,一个按钮启动协程计算,另一个直接计算结果。由于2个方法都是计算同样的结果,计算量比较大,所以直接计算出现了暂时的卡死情况。 


这个方法是协程的写法,在C#中协程要定义为IEnumerator 这个类型,javascript中不需要。

yield return 1;这句话表示返回1帧的结果。在i为100的整数时,就返回一次结果,这样可以避免大量的计算卡死。

float result;  
    IEnumerator GetResult()  
    {  
        for (int i = 0; i < 1000; i++)  
        {  
            for (int j = 0; j < 100000; j++)  
            {  
                result += (i + j);  
                  
            }  
            if(i%100==0)  
                yield return 1;  
              
        }  
    }  


 这个方法就是直接计算结果,由于运算量比较大,所以界面会卡死,这样就可以体现出用协程的好处了。

使用IEnumerator 这个类型时,必须用yield return来返回结果,参数为数字时表示为帧数。

如yield return 1 表示每一帧返回一次结果。

本文转载于 http://www.cnblogs.com/xpvincent/archive/2013/07/13/3188257.html


以上两篇文章是我了解,学习协程的较为浅显易懂的文章。解释的很清楚。随着之后我在代码中的不断使用和尝试,有机会带来自己的心得体会。

下面贴出两篇不错的资料,供进阶阅读

http://blog.csdn.net/huang9012/article/details/38492937

http://dsqiu.iteye.com/blog/2049743



就目前理解,简单说一下自己体会啊~

1,在加载比较大的预制,资源的时候,用yield ruturn 来加载。这样避免了在游戏中某一帧加载过多资源导致卡死的情况

2,可以用协程嵌套,做计时器什么的,方便自己对对象行为的控制(详见之后)


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值