您的位置:首页 > 移动开发 > Unity3D

理解Unity中的协程的使用

2015-01-28 08:30 225 查看
今天,换项目组以后,不用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,可以用协程嵌套,做计时器什么的,方便自己对对象行为的控制(详见之后)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: