2013-06-06 17 views
16

Sono confuso e curioso su come funziona coroutines (in Unity3D e forse in altri posti). Coroutine è una nuova discussione? di unità documentation hanno detto:Coroutine è una nuova discussione in Unity3D?

Un coroutine è una funzione che può sospendere l'esecuzione (resa) finché termina la proposta YieldInstruction.

E hanno C# esempi here:

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

Ho molte domande su questo esempio:

  1. Nell'esempio di cui sopra, che la linea è coroutine? WaitAndPrint() è una coroutine? WaitForSeconds() è una coroutine?

  2. In questa riga: yield return new WaitForSeconds(waitTime);, perché sono presenti sia yield sia return? Ho letto in Unity documentation che "La dichiarazione di rendimento è un tipo speciale di rendimento, che garantisce che la funzione continui dalla riga dopo la dichiarazione di rendimento la prossima volta che viene chiamata." Se yield è uno speciale return, che cosa fa return qui?

  3. Perché dobbiamo restituire un IEnumerator?

  4. StartCoroutine avvia una nuova discussione?

  5. Quante volte è stato chiamato WaitAndPrint() nell'esempio precedente? yield return new WaitForSeconds(waitTime); è stato effettivamente restituito? Se sì, suppongo che WaitAndPrint() sia stato chiamato due volte nel codice precedente. E immagino che StartCoroutine() chiami più volte WaitAndPrint(). Tuttavia, ho visto another Unity documentation che dice: "L'esecuzione di una coroutine può essere messa in pausa in qualsiasi momento usando la dichiarazione di rendimento.Il valore di ritorno di rendimento specifica quando viene ripresa la coroutine." Queste parole mi fanno pensare che lo WaitAndPrint() in realtà non sia tornato; è stato semplicemente messo in pausa; Stava aspettando il WaitForSeconds() per tornare. Se questo è il caso, allora il codice di cui sopra WaitAndPrint() è stato chiamato solo una volta e StartCoroutine era solo responsabile dell'avvio della funzione, non la chiama più volte.

+0

In risposta alla domanda nel titolo, le coroutine ** NON ** avviano un nuovo thread e di per sé non hanno alcuna connessione ai thread. Non dimenticare che Unity3D è fondamentalmente basato su frame. I MonoBehaviours sono un concetto basato su frame. Le coroutine - in Unity - sono intrinsecamente connesse a questo paradigma. I thread sono totalmente non coinvolti. – Fattie

+0

Mi imbatto in questo tutorial http://www.unitygeek.com/coroutines-in-unity3d/, spiega molto bene l'uso delle coroutine in unity3d –

risposta

16

coroutine sono una tecnica potente estremamente utilizzata per emulare i tipi di funzioni supportate dal asincrona/attendono in .net4.5, ma nelle versioni precedenti (C#> = v2.0).

Microsoft CCR (prendere una lettura) impiega anche (impiegato?) Questo approccio.

Raccogliamo una cosa. yield da solo non è valido ed è sempre seguito da return o break.

Pensare a un IEnumerator standard (che non produce messaggi di controllo del flusso).

IEnumerator YieldMeSomeStuff() 
{ 
    yield "hello"; 
    Console.WriteLine("foo!"); 
    yield "world"; 
} 

Ora:

IEnumerator e = YieldMeSomeStuff(); 
while(e.MoveNext()) 
{ 
    Console.WriteLine(e.Current); 
} 

Qual è l'uscita?

 
hello 
foo! 
world 

Notate come, la seconda volta che abbiamo chiamato MoveNext, prima che il prodotto Enumerator "mondo" del codice corse all'interno del Enumerator. Ciò significa che nell'Enumeratore possiamo scrivere codice che viene eseguito fino a quando non raggiunge un'istruzione yield return, quindi si interrompe semplicemente fino a quando qualcuno chiama MoveNext (a mano libera con tutti gli stati/variabili catturati in modo preciso, così possiamo riprendere da dove avevamo interrotto). Dopo una chiamata MoveNext, il successivo bit di codice dopo l'istruzione yield return può essere eseguito fino al raggiungimento di un altro yield return. Quindi ora possiamo controllare l'esecuzione del codice tra le istruzioni yield return con la chiamata MoveNext all'Enumeratore.

Ora, dicono, invece di cedere stringhe, la nostra Enumerator dovesse produrre un messaggio che dice al chiamante di MoveNext, "si prega di rimanere in giro per x (waittime) secondi prima di chiamare di nuovo MoveNext". Il chiamante è stato scritto per "capire" una varietà di messaggi. Questi messaggi saranno sempre sulla falsariga di "per favore attendi che tali eventi avvengano prima di chiamare di nuovo MoveNext".

Ora abbiamo un potente mezzo per sospendere e riavviare il codice che richiede che siano soddisfatte altre condizioni prima che possa procedere, senza dover scrivere quella funzionalità in un altro metodo, come fare roba asincrona senza le coroutine. Senza le coroutine, sei costretto a passare attorno a un orribile oggetto asincrono di stato che avresti bisogno di assemblare manualmente per catturare lo stato tra la fine di un metodo e l'inizio di un altro dopo un po 'di async). Coroutine eliminano questo perché l'ambito è preservato (dal compilatore magico), quindi le variabili locali persistono su cose asincrone di lunga durata.

StartCoroutine avvia semplicemente l'intero processo. Chiama MoveNext sull'Enumeratore ... qualche codice viene eseguito nell'enumeratore ... L'enumeratore restituisce un messaggio di controllo che informa il codice in StartCoroutine quando chiama di nuovo MoveNext. Questo non deve accadere in una nuova discussione, ma può essere utile in scenari multithreading perché possiamo chiamare MoveNext da thread diversi e controllare dove il lavoro è fatto.

+2

E per gli altri, [Pagina dell'ordine di esecuzione di Unity] (http: // docs .unity3d.com/Documentation/Manual/ExecutionOrder.html) che mostra le coroutine in esecuzione dopo Update(). – Jerdak

Problemi correlati