Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

In the Unity3D game engine, a common code sequence for getting remote data is this:

WWW www = new WWW("http://remote.com/data/location/with/texture.png");
yield return www;

What is the underlying mechanism here?

I know we use the yield mechanism in order to allow the next frame to be processed, while the download is being completed. But what is going on under the hood when we do the yield return www ?

What method is being called (if any, on the WWW class)? Is Unity using threads? Is the "upper" Unity layer getting hold of www instance and doing something?

EDIT:

  • This question is specifically about Unity3D internals. I'm not interested in explanations of how yield statement works in C#. Instead, I'm looking for an inside view of how Unity deals with these constructions, to allow, for example, to WWW to download a piece of data in a distributed manner across several frames.
share|improve this question
    
Note that using yield return for asynchronous operations is a hack. In a "real" C# program, you'd use a Task for this. Unity is probably not using them because it was created before .Net 4.0, when Task was introduced. –  BlueRaja - Danny Pflughoeft Feb 1 at 6:40

4 Answers 4

up vote 7 down vote accepted

This is the C# yield keyword in action - its not doing anything special with the www object, rather its means something special for the method its contained in. Specifically this keyword can only be used in a method which returns an IEnumerable (or IEnumerator), and is used to indicate what object will be "returned" by the enumerator when MoveNext is called.

It works because the compiler converts the entire method into a separate class which implements IEnumerable (or IEnumerator) using a state machine - the net result is that the body of the method itself is not executed until someone enumerates through return value. This will work with any type, there is absolutely nothing special about WWW, rather its the containing method which is special.

Take a look at Behind the scenes of the C# yield keyword for some more insight into what sort of code the C# compiler generates, or just experiment and inspect the code yourself using something like IL Spy


Update: To clarify

  • When Unity calls a coroutine that contains a yield return statement all that happens is that an enumerator is returned - none of the method body is executed at this point
  • To get the method body to execute Unity must call MoveNext on the iterator in order to get the first value in the sequence. This causes the method to execute up to the first yeild return statement, at which point the caller resumes (and presumably Unity goes on to render the rest of the frame)
  • As I understand it Unity normally then goes on to call the MoveNext method on the iterator once each subsequent frame, causing the method to execute again up to the next yield return statement once each frame, until either the end of the method or a yield break statement is reached (indicating the end of the sequence)

The only special bit here (and in a couple of other cases) is that Unity doesn't advance this particular iterator the next frame, instead it only advances the iterator (causing the method to continue executing) when the download has completed. Although there does appear to be a base YieldInstruction class which presumably contains a generic mechanism for signalling to Unity when an iterator should be advanced, the WWW class doesn't appear to inherit from this class so I can only assume that there is a special case for this class in the Unity engine.

Just to be clear - the yield keyword doesn't do anything special to the WWW class, rather its the special handling that Unity gives to the members of the returned enumeration which causes this behaviour.


Update the second: As for the mechanism that WWW uses to download web pages asynchronously it probably uses either the HttpWebRequest.BeginGetResponse Method which will internally use asynchronous IO or alternatively it could use threads (either creating a dedicated thread or by using a thread pool).

share|improve this answer
3  
Actually, in Unity, something special does happen to a WWW object when it is yielded, see WWW's reference. –  Eric Nov 14 '12 at 15:21

yield seems to be mainly used in Unity in a coroutine context. To read more about coroutines and why they use C#'s yield I recommend this blog article: Unity3D coroutines in detail. Most of the research in this answer comes from that article.

Coroutines in Unity are used to encapsulate tasks which:

  1. may take longer than a frame to be rendered (thereby causing slowdowns), and
  2. can be performed separately from the game loop (because the result does not need to be available for the current frame).

Examples of these kinds of tasks are pathfinding (re)calculations or, as is the case in your question, getting data from a website.

To answer your subquestions (in a slightly modified order):

What method is being called (if any, on the WWW class)? Is the "upper" Unity layer getting hold of www instance and doing something?

Unity's WWW class is designed to be yielded from a coroutine. According to the comments on the blog article linked above, the speculative block of code (the '"upper" layer') about YieldInstructions actually contains a switch which also checks for yielded WWWs. This code then makes sure the coroutine will finish automatically when the download is done, as described in WWW's reference.

Is Unity using threads?

In this case, to download the data "without blocking the rest of the game": yes, most likely. (And threading is definitely used to decompress the downloaded data, as evidenced by WWW.threadPriority.)

share|improve this answer
    
nice! I saw the comment altdevblogaday.com/2011/07/07/unity3d-coroutines-in-detail/… and it seems that WWW is treated specially. So I'd like to know how this is accomplished, in order to allow the download to be made across several frames, without using threads? –  thyandrecardoso Nov 14 '12 at 15:22
    
Good point! I suppose there must be some threading going on at that level after all, I'll edit my answer to reflect that. –  Eric Nov 14 '12 at 15:29
1  
@thyandrecardoso I'd guess it uses HttpWebRequest.BeginGetResponse or similar, however you could decompile the assembly to confirm this if it really mattered to you. –  Justin Nov 14 '12 at 16:35
    
for now, I'm really only waiting for the "best explanation"... would be great if anyone from Unity dev team gave the "correct answer" 8-)... ultimately, I think the real implementation won't be far off the ones already given here... I don't have an actual need to decompile the assembly and know all this for sure though. But I might try it later :) –  thyandrecardoso Nov 14 '12 at 16:43

Unfortunately, WWW is implemented internally as native code, meaning that we can't look at the code. From experimentation I can say that

  1. WWW is not derived from YieldInstruction, so whatever happens when you yield it must be handled by special-case code.
  2. I've never obseved any difference between

    yield return www;
    

    and

    while(!www.isDone)
        yield return null;
    

    I think that's the most logical way to implement it, and most probably that's what is going on under the hood. But I don't know for sure.

  3. Unity does not start a new thread for downloading, at least on some platforms (iOS, webplayer). Or if it does, it sets WWW.isDone on the main thread. I know this because this code:

    while(!www.isDone)
        Thread.Sleep(500);
    

    doesn't work.

I don't think you can have more specific answers unless someone with access to Unity3d's source code comes here.

share|improve this answer
    
Yup. Really nice insights! Thanks! Even though not launching a thread per se, the most probable thing that might be happening is WWW (or the engine layer) using HttpWebRequest.BeginGetResponse (or something like it)... right? Something completely async must occur either way... the download can't be "paused". –  thyandrecardoso Nov 15 '12 at 10:58
    
** can't be "paused" between frames, I mean. –  thyandrecardoso Nov 15 '12 at 13:05

Since Unity3D uses C# as their scripting engine I suppose its the standard yield keyword which is built into C#. Basically what it means is that it returns the value of www already so that you can continue while the next iteration it will return the next value, etc... Yield basically creates a state machine and iterator in the background.

share|improve this answer
    
Yes, I think I have the basic notions about the yield keyword. However, what is happening during the constructor of WWW that allows for that "state machine"? I mean, "yield return www" does not seem to be calling anything inside the WWW class... When you say "it means is that it returns the value of www already", what is the www instance value? What will that instance do on the next "iteration" ? –  thyandrecardoso Nov 14 '12 at 12:56
1  
In Unity coroutines, yielding WWW is a special case, see WWW's reference. Furthermore, I'm not sure yield creates anything. The iterator context is created by implementing IEnumerable or using it as a return type. "State machine" seems off too. Sure, there is state, but that alone is not a sufficient property, right? Maybe you could elaborate on that. –  Eric Nov 14 '12 at 15:19
    
Here is a good reference on the normal C# behavior. shadowcoding.blogspot.nl/2009/01/yield-and-c-state-machine.html . Yield generates a lot of code to keep track of where it is in the iterator. About Unity's special case yielding WWW, I didn't know but according to the docs it doesn't have anything todo with the normal C# keyword, that's very confusing, they could'be just made it an async method. –  Roy T. Nov 15 '12 at 7:15

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.