[英]Is coroutine a new thread in Unity3D?
关于协同程序 (在Unity3D和其他地方)如何工作,我感到困惑和好奇。 coroutine是新线程吗? 他们说Unity的文档 :
协程是一个可以暂停执行(yield)直到给定的YieldInstruction完成的函数。
他们在这里有C#示例:
using UnityEngine;
using System.Collections;
public class example : MonoBehaviour {
void Start() {
print("Starting " + Time.time);
StartCoroutine(WaitAndPrint(2.0F));
print("Before WaitAndPrint Finishes " + Time.time);
}
IEnumerator WaitAndPrint(float waitTime) {
yield return new WaitForSeconds(waitTime);
print("WaitAndPrint " + Time.time);
}
}
我对这个例子有很多疑问:
在上面的例子中,哪一行是协程? 是的WaitAndPrint()
是一个协程吗? 是WaitForSeconds()
是一个协程吗?
在这一行中: yield return new WaitForSeconds(waitTime);
,为什么yield
和return
都存在? 我在Unity文档中读到“yield语句是一种特殊的返回,它确保函数将在下次调用yield语句后继续执行。” 如果yield
是一个特殊的return
,那么return
在这里做什么?
为什么我们必须返回IEnumerator
?
StartCoroutine
是否启动了一个新线程?
在上面的例子中调用了WaitAndPrint()
多少次? yield return new WaitForSeconds(waitTime);
真的回来了? 如果是,那么我猜WaitAndPrint()
在上面的代码中被调用了两次。 我猜StartCoroutine()
多次调用WaitAndPrint()
。 但是,我看到另一个Unity文档说:“可以使用yield语句在任何时候暂停执行协程。yield return value指定何时恢复协程。” 这些话让我觉得WaitAndPrint()
实际上还没有返回; 它只是暂停了; 它正在等待WaitForSeconds()
返回。 如果是这种情况,那么在上面的代码中, WaitAndPrint()
只被调用一次,而StartCoroutine
只负责启动该函数,而不是多次调用它。
协同程序是一种非常强大的技术,用于模拟.net4.5中async / await支持的各种功能,但在早期版本中(c#> = v2.0)。
Microsoft CCR (读取)也采用(使用?)这种方法。
让我们放开一件事。 单独的yield
无效,并且始终是return
或break
。
想想标准的IEnumerator(它不会产生流控制消息)。
IEnumerator YieldMeSomeStuff()
{
yield "hello";
Console.WriteLine("foo!");
yield "world";
}
现在:
IEnumerator e = YieldMeSomeStuff();
while(e.MoveNext())
{
Console.WriteLine(e.Current);
}
什么输出?
hello foo! world
请注意,在枚举器产生“世界”之前,我们第二次调用MoveNext
,在枚举器中运行了一些代码。 这意味着在Enumerator中,我们可以编写执行代码直到它yield return
语句,然后暂停直到有人调用MoveNext
(轻松地将所有状态/变量整齐地捕获,所以我们可以从我们中断的地方继续) 。 在MoveNext
调用之后, yield return
语句之后的下一位代码可以运行,直到达到另一个yield return
。 因此,我们现在可以通过对Enumerator的MoveNext
调用来控制yield return
语句之间的代码执行。
现在,我们的枚举器不是产生字符串,而是产生一条消息,告诉MoveNext
的调用者, “请再次调用MoveNext
之前暂停x(waitTime)秒” 。 写入调用者是为了“理解”各种消息。 这些消息将始终沿着“请等待再次调用MoveNext
之前发生这样的事情” 。
现在我们有一个强大的暂停和重新启动代码的方法,它需要满足其他条件才能继续,而不必将该功能写入另一个方法,比如在没有协同程序的情况下执行异步操作。 如果没有协同程序,你就会强行传递一个可怕的异步状态对象,你需要手动组装以捕获一个方法结束和另一个异步之后的另一个方法的启动之间的状态。 协同程序消除了这种情况,因为范围被保留(通过编译器魔术),因此您的本地变量会持久存在于长期存在的异步内容中。
StartCoroutine
只是启动整个过程。 它在Enumerator上调用MoveNext
...一些代码在Enumerator中运行...枚举器产生一条控制消息,它通知StartCoroutine
的代码何时再次调用MoveNext
。 这不需要在新的Thread中发生,但在多线程场景中可以很方便,因为我们可以从不同的线程调用MoveNext
并控制工作的完成位置。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.