尝试了解 Unity3D 中的 c# 产量
本文关键字:产量 中的 Unity3D 了解 | 更新日期: 2023-09-27 18:36:47
我有一个类。它有一个可以做很多工作的方法。我不希望在程序完成工作时挂起。我知道yield
会为我做这件事。
void Start() {
DoWork(10,10);
}
void DoWork (int x, int y) {
for (int i=0; i < x; i++) {
for (int j=0; j < y; j++) {
// Stuff
}
}
}
如果我添加这样的yield
void Start() {
DoWork(10, 10);
}
IEnumerable DoWork (int x, int y) {
for (int i=0; i < x; i++) {
for (int j=0; j < y; j++) {
// Stuff
}
Debug.Log (1);
yield return null;
}
}
没有完成任何工作,最重要的是,我根本没有看到任何日志语句。
如何yield
我的代码,以便程序不会冻结?
这是 Unity3D 引擎,因此您的协程需要返回 IEnumerator 才能有效:
void Start() {
StartCoroutine(DoWork(10, 10));
}
IEnumerator DoWork (int x, int y) {
for (int i=0; i < x; i++) {
for (int j=0; j < y; j++) {
// Stuff
}
Debug.Log (1);
yield return null;
}
}
这绝不是多线程。它就像在更新和后期更新之间每帧运行一次更新一样,除非您使用
yield return new WaitForEndOfFrame();
然后推迟到渲染过程之后。它的作用是创建一个协程类型的新对象,并将其放在协程的调用 MonoBehavior 堆栈上。
这是一种执行一些重复操作的方法,但在达到产量时始终返回到主程序。然后它将在下一帧从那里回来。
您需要使用 StartCoroutine 方法:
void Start() {
StartCoroutine(DoWork(10, 10));
}
IEnumerator DoWork (int x, int y) {
// (A)
yield return null;
// (B)
for (int i=0; i < x; i++) {
for (int j=0; j < y; j++) {
// Stuff
}
Debug.Log (1);
yield return null;
// (C)
}
}
你的代码是逐段执行的,其中步骤的分隔符是 yield 运算符,即当框架第一次调用 MoveNext() 时 - 代码 (A) 将被执行,当它第二次调用 MoveNext() 时 - 代码 (B) 将被执行,然后是代码 (C),依此类推。
当您添加 yield
语句时,编译器实际上会生成一个私有类,该类充当实现IEnumerable
的状态机。因此,除非您枚举该方法的结果,否则不会调用从原始方法包装的任何代码 - 在您的示例中,您丢弃了返回值,因此不会发生任何事情。
Yield
关键字用于C#中的延迟加载/计算支持。
尝试执行以下操作:
var result = DoWork().ToList();
这将强制评估 DoWork() 方法,您将看到日志记录正在进行。
yield就像 C# yields 一样工作。团结不会以任何方式影响这一点。
yield
是一个关键字,用于允许对一组返回值进行枚举。
IEnumerator<int> MyEnumerationMethod()
{
yield return 5;
yield return 1;
yield return 9;
yield return 4;
}
void UserMethod1()
{
foreach (int retVal in MyEnumerationMethod())
Console.Write(retVal + ", ");
// this does print out 5, 1, 9, 4,
}
void UserMethod2()
{
IEnumerator<int> myEnumerator = MyEnumerationMethod();
while (myEnumerator.MoveNext())
Console.Write(myEnumerator.Current + ", ");
// this does print out 5, 1, 9, 4,
}
UserMethod1() 和 UserMethod2() 几乎相同。UserMethod1() 只是 UserMethod2() 的 C# 语法糖版本。
Unity 使用此语言功能来实现协程:
当您调用StartCoroutine()
并向其传递IEnumerator
时,Unity 会存储此枚举器并首次调用MoveNext()
。这将导致MyEnumerationMethod()
被调用并执行,直到第一个yield return
。此时,MoveNext()
返回,可以通过查看枚举器的 Current
属性来检索第一个结果 (5)。
现在,Unity 会定期检查 Current
属性,并根据其值决定是否需要再次调用MoveNext()
。Current
的值可能是WaitForEndOfFrame
的实例,WWW
的实例或其他任何实例,并且根据时间决定调用MoveNext()
。
再次调用 MoveNext()
后,MyEnumerationMethod()
的执行将在上次中断的位置继续执行,并执行直到执行下一个yield return
。等等。
这就是 Unity 中屈服和协程的全部内容。