Coroutines & Yield


協同的理解

http://blog.163.com/hj_0467/blog/static/74252563201011711845180/

http://wg2009perfect.blog.163.com/blog/static/127997663201211111222126/

摘要下:

1.

coroutine, 中文翻譯“協程”。這個概念可能有點冷門,不過百度之,說是一種很古老的編程模型了,以前的操作系統里進程調度里用到過,現在操作系統的進程調度都是根據 時間片和優先級來進行輪換,以前是要程序自己來釋放cpu的控制權,一直不釋放一直也就占用着cpu,這種要求程序自己來進行調度的編程模型應該就叫“協 程”了。

協程和線程差不多,線程的調度是由操作系統完成的,協程把這項任務交給了程序員自己實現,當然也就可以提高靈活性,另外協程的開銷比線程要小,在程序里可以開更多的協程。

一些語言里自帶了對coroutine的實現,比如lua。c里面雖然沒有coroutine,不過windows下提供了一種叫fiber的機制,叫做“纖程”,算是一種輕量級線程。

 

2.

一。什么是協同程序

       協同程序,即在主程序運行時同時開啟另一段邏輯處理,來協同當前程序的執行。換句話說,開啟協同程序就是開啟一個線程

 

二。協同程序的開啟與終止

       在Unity3D中,使用MonoBehaviour.StartCoroutine方法即可開啟一個協同程序,也就是說該方法必須在MonoBehaviour或繼承於MonoBehaviour的類中調用。

       在Unity3D中,使用StartCoroutine(string methodName)和StartCoroutine(IEnumerator routine)都可以開啟一個線程。區別在於使用字符串作為參數可以開啟線程並在線程結束前終止線程,相反使用IEnumerator 作為參數只能等待線程的結束而不能隨時終止(除非使用StopAllCoroutines()方法);另外使用字符串作為參數時,開啟線程時最多只能傳遞 一個參數,並且性能消耗會更大一點,而使用IEnumerator 作為參數則沒有這個限制。

        在Unity3D中,使用StopCoroutine(string methodName)來終止一個協同程序,使用StopAllCoroutines()來終止所有可以終止的協同程序,但這兩個方法都只能終止該 MonoBehaviour中的協同程序。

        還有一種方法可以終止協同程序,即將協同程序所在gameobject的active屬性設置為false,當再次設置active為ture時,協同程 序並不會再開啟;如是將協同程序所在腳本的enabled設置為false則不會生效。這是因為協同程序被開啟后作為一個線程在運行,而 MonoBehaviour也是一個線程,他們成為互不干擾的模塊,除非代碼中用調用,他們共同作用於同一個對象,只有當對象不可見才能同時終止這兩個線 程。然而,為了管理我們額外開啟的線程,Unity3D將協同程序的調用放在了MonoBehaviour中,這樣我們在編程時就可以方便的調用指定腳本 中的協同程序,而不是無法去管理,特別是對於只根據方法名來判斷線程的方式在多人開發中很容易出錯,這樣的設計保證了對象、腳本的條理化管理,並防止了重 名。

我的一些粗淺小結:

1.Coroutines顧名思議是用來協助主要進程的,在Unity中感覺就是一個可動態添加和移除的Update()函數。它的調用在所有Update函數之后。

Unity原文:

  • If you start a coroutine in LateUpdate it will also be called after LateUpdate just before rendering.
  • Coroutines are executed after all Update functions.

2.yield就像是一個紅綠燈,在滿足緊跟在它后面的條件之前,這個協程會掛起,把執行權交給調用它的父函數,滿足條件時就可以執行yield下面的代碼。

Unity原文:

Normal coroutine updates are run after the Update function returns. A coroutine is function that can suspend its execution (yield) until the given given YieldInstruction finishes. Different uses of Coroutines:

  • yield;等待 all Update functions 已被call過,The coroutine will continue on the next frame.
  • yield WaitForSeconds(2);Continue after a specified time delay, after all Update functions have been called for the frame
  • yield WaitForFixedUpdate();Continue after all FixedUpdate has been called on all scripts
  • yield WWWContinue after a WWW download has completed.
  • yield StartCoroutine(MyFunc); Chains the coroutine, and will wait for the MyFunc coroutine to complete first.

 

協同的用法

Yield中斷:(有中斷就代表程序停在該處,等待yield后的時間結束再繼續執行后面的語句。)

http://unity3d.com/support/documentation/ScriptReference/index.Coroutines_26_Yield.html

http://game.ceeger.com/Script/Overview/Overview.Coroutines_Yield.html

注意:

  • 在unity C#中yield(中斷)語句必須要在IEnumerator類型里

  • C#方法,方法的返回類型為IEnumerator,返回值如(eg: yield return new WaitForSeconds(2); 或者 yield return null;)。

  • yields不可以在Update或者FixedUpdate里使用。


示例:
這個例子將執行Do,但是do之后的print會立刻執行:

using UnityEngine;
using System.Collections;

public class example : MonoBehaviour {
public static IEnumerator Do() {
  print("Do now");
  yield return new WaitForSeconds(2);
  print("Do 2 seconds later");
}
void Awake() {
  Do();    //執行DO,但是do后的語句繼續執行
  print("This is printed immediately");
}

這個例子將執行Do,並等待,直到Do完成再執行其他語句:

using UnityEngine;
using System.Collections;

public class example : MonoBehaviour {
    IEnumerator Do() {
        print("Do now");
        yield return new WaitForSeconds(2);
        print("Do 2 seconds later");
    }
    IEnumerator Awake() {
        yield return StartCoroutine("Do");    //Yield StartCoroutine就代表中斷式的協同工作
        print("Also after 2 seconds");
        print("This is after the Do coroutine has finished execution");
    }
}

Coroutine協同:(為什么要有Coroutine的概念? 因為有中斷的存在,試想一個程序都靠Yield來暫停的話,如何做到一個事件暫停的過程中,暫停過程中繼續執行后面的程序? 那么就要靠Coroutine來實現。)

http://unity3d.com/support/documentation/ScriptReference/MonoBehaviour.StartCoroutine.html?from=YieldInstruction 

http://game.ceeger.com/Script/MonoBehaviour/MonoBehaviour.StartCoroutine.html

  • 可以在UPdate或者FixedUpdate里使用coroutine
  • 這里有兩種:StartCoroutine(協同工作) 和 yield return StartCoroutine(中斷式的協同工作)
  • 有yield的代表先執行完本語句(不管多長時間),或者執行完本yield方法調用,才執行后續語句。例如StartCoroutine(WaitAndPrint(2.0F)),繼續執行StartCoroutine后面的語句,
  • 沒有yield的代表繼續順序執行。例如:yield return StartCoroutine(WaitAndPrint(2.0F)),代表StartCoroutine(WaitAndPrint(2.0F))函數里等待全部執行完,再執行StartCoroutine后面的語句

 StartCoroutine的例子:

// In this example we show how to invoke a coroutine and continue executing
// the function in parallel.
// 此例演示如何調用協同程序和它的執行
function Start() {
    // - After 0 seconds, prints "Starting 0.0"
    // - After 0 seconds, prints "Before WaitAndPrint Finishes 0.0"
    // - After 2 seconds, prints "WaitAndPrint 2.0"
    // 先打印"Starting 0.0"和"Before WaitAndPrint Finishes 0.0"兩句,2秒后打印"WaitAndPrint 2.0"
    print ("Starting " + Time.time );
    // Start function WaitAndPrint as a coroutine. And continue execution while it is running
    // this is the same as WaintAndPrint(2.0) as the compiler does it for you automatically
    // 協同程序WaitAndPrint在Start函數內執行,可以視同於它與Start函數同步執行.
    StartCoroutine(WaitAndPrint(2.0)); 
    print ("Before WaitAndPrint Finishes " + Time.time );
}

function WaitAndPrint (waitTime : float) {
    // suspend execution for waitTime seconds
    // 暫停執行waitTime秒
    yield WaitForSeconds (waitTime);
    print ("WaitAndPrint "+ Time.time );
}

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);
    }
}

yield return StartCoroutine的例子:

// In this example we show how to invoke a coroutine and wait until it 
// is completed
// 在這個例子中我們演示如何調用協同程序並直到它執行完成.
function Start() {
    // - After 0 seconds, prints "Starting 0.0"
    // - After 2 seconds, prints "WaitAndPrint 2.0"
    // - After 2 seconds, prints "Done 2.0"
    // 0秒時打印"Starting 0.0",2秒后打印"WaitAndPrint 2.0"和"Done 2.0"
    print ("Starting " + Time.time );
    // Start function WaitAndPrint as a coroutine. And wait until it is completed.
    // the same as yield WaitAndPrint(2.0);
    // 運行WaitAndPrint直到完成
    yield StartCoroutine(WaitAndPrint(2.0));
    print ("Done " + Time.time );
}

function WaitAndPrint (waitTime : float) {
    // suspend execution for waitTime seconds
    // 等待waitTime秒
    yield WaitForSeconds (waitTime);
    print ("WaitAndPrint "+ Time.time );
}

C#版本

using UnityEngine;
using System.Collections;

public class example : MonoBehaviour {
    IEnumerator Start() {
        print("Starting " + Time.time);
        yield return StartCoroutine(WaitAndPrint(2.0F));
        print("Done " + Time.time);
    }
    IEnumerator WaitAndPrint(float waitTime) {
        yield return new WaitForSeconds(waitTime);
        print("WaitAndPrint " + Time.time);
    }
}

 C#中的Coroutine與JavaScript中的區別:

1:Coroutines 必須要是 IEnumerator 返回類型:

IEnumerator MyCoroutine()
{
    //This is a coroutine
}

2:在C#中要使用 yield return而不是yield :

Remember that we need to return an IEnumerable, so the Javascript yield; becomes yield return 0; in C#

IEnumerator MyCoroutine()
{
    DoSomething();
    yield return 0; //Wait one frame, the 0 here is only because we need to return an IEnumerable
    DoSomethingElse();
}

since C# requires you to use the new operator to create objects, if you want to use WaitForSeconds you have to use it like this:

IEnumerator MyCoroutine()
{
    DoSomething();
    yield return new WaitForSeconds(2.0f);  //Wait 2 seconds
    DoSomethingElse();
}

3:調用Coroutine要使用 StartCoroutine 方法:

public class MyScript : MonoBehaviour
{
    void Start()
    {
        StartCoroutine(MyCoroutine());
    }
 
    IEnumerator MyCoroutine()
    {
        //This is a coroutine
    }
}

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM