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.
Answer
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 firstyeild 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 nextyield return
statement once each frame, until either the end of the method or ayield 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).
No comments:
Post a Comment