July 23, 2023

协程原理的简单认识

首先需要明确的一点是,协程不是线程,协程依旧在主线程中进行

Unity中的协程通过[[迭代器]]实现,通过一个IEnumerator关键字实现一个迭代器方法,所以实际上协程的原理并不难

使用Update模拟协程

我们声明一个Enumerable类

1
2
3
4
5
6
7
8
9
public class CoroutineExample : IEnumerable  
{
public IEnumerator GetEnumerator()
{
yield return 1;
yield return 2;
yield return 3;
}
}

首先尝试在Start函数中用while和foreach来进行迭代

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void Start()  
{
CoroutineExample cor = new CoroutineExample();
IEnumerator enumerator = cor.GetEnumerator();
while (enumerator.MoveNext())
{
Debug.Log(enumerator.Current.ToString());
}
//////////或者/////////
foreach (var i in cor)
{
Debug.Log(i);
}
}

两者的运行结果一致

1
2
3
4
5
6
1
2
3
1
2
3

接下来,我们不使用while或者foreach枚举元素,我们使用Update函数,每一帧执行MoveNext来进行枚举

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private CoroutineExample cor;  
private IEnumerator enumerator;
void Start()
{

cor = new CoroutineExample();
enumerator = cor.GetEnumerator();
}

void Update()
{
if (enumerator.MoveNext())
{
Debug.Log(enumerator.Current);
}
}

运行效果一致

1
2
3
1
2
3

使用Unity的协程

接下来我们使用StartCoroutine方法启动协程(为了方便查看,修改了GetEnumerator的代码)

1
2
3
4
5
6
7
8
9
public IEnumerator GetEnumerator()  
{
Debug.Log("1");
yield return 1;
Debug.Log("2");
yield return 2;
Debug.Log("3");
yield return 3;
}

在Start函数中启动协程

1
2
3
4
5
6
void Start()  
{
cor = new CoroutineExample();
enumerator = cor.GetEnumerator();
StartCoroutine(enumerator);
}

运行结果为

1
2
3
1
2
3

原理

由此可见,通过Update模拟协程和使用StartCoroutine方法启动协程的效果似乎是差不多的,Unity内部的执行逻辑也是一步一步的执行程序块,StartCoroutine会不停调用MoveNext方法,直到迭代结束,Coroutine的原理大致是每一帧调用IEnumerator的MoveNext方法,这也就是为什么我们需要定义一个返回值为IEnumerator的方法

About this Post

This post is written by Yuan, licensed under CC BY-NC 4.0.

#Unity