[Mono-dev] Coroutines, Monoco, and why we love them.

Lucas Meijer lucas at lucasmeijer.com
Fri Nov 21 12:55:36 EST 2008


At the Unite conference, I was delighted to meet up with Miguel, as that 
would let me underline the parts of mono (existing or nonexisting) that 
are very important to our mono using projects. He asked me if I could 
write a message to mono-dev explaining not only privately why these 
things are important to us.

We're working on a multiplayer MMO game. The backend is written in c# 
running on mono, the client uses Unity3D, whose scripting is powered by 

Eariler in the project the plan was to write the backend in Stackless 
Python, because of its coroutines support.  I was thrilled to find Tomi 
Valkeinen's MonoCo. (http://www.bat.org/~tomba/monoco.html) (Thanks 
Tomi!).  MonoCo brings stackless style coroutines to mono, and this made 
us switch to mono.

Monoco makes my life a lot easier.  Often monoco or stackless python are 
mistaken for a solution to multithreaded problems. It is not. I consider 
it an elegant implementation of asynchronous programming.  Imagine this 
piece of backend code asking a player what move to make:

//excuse the c# <> pseudocode mix.

public class ImaginaryBackend
   public void NeverEndingGameLoop()
         while (players.Count > 0)
               PlayerAction pa = 
               //this call has blocked our "microthread'
               //the returned message is immidiately available on the 
next line of code.

               if (!pa.Validate()) pa = new EndTurnPlayerAction();

where the meat is in the "AskWhatToDo" method call.  Somewhere in this 
methodcall, a request packet gets sent to our player, with some 
questionID.  this microthread then gets put "in the fridge".  while the 
packet is travelling trough a series of tubes, my other microthreads are 
happily running.   When the player responds (tagged with the same 
questionID),  the network reading code sees that there is a microthread 
in the fridge, that is waiting for an answer to the question that this 
incoming message is answering.   So it "requeues" the microthread, and 
supplies it the incoming message.

So I can program as if the call were a blocking call, but the behaviour 
does not block my (most likely only) thread.  my other code can keep on 
running.   Basically it's an alternative to a state machine.

Another example is in scripting behaviour for computer controlled agents 
in a game:

public class AnnoyingDragon
   public void MicroThreadEntryPoint()

With each of these calls "blocking" the microthread untill the action 
has actually completed..  The non-coroutines solution to this problem 
would look like:

public class AnnoyingDragon
   public void Update()
      DragonState mystate = DragonState.Idle;

      switch (mystate)
           case DragonState.Nothing:
               mystate = DragonState.WalkingToBridge;
           case DragonState.WalkingToBridge:
               if (!closeEnoughTo(bridge))  return MoveMoreTowards(bridge);
               mystate = DragonState.OpeningBridge:
          case DragonState.OpeningBridge:
               if (!Bridge.FullyOpen())  return Wait();
               mystate = DragonState.WalkingToCastle;
         case DragonState.WalkingToCastle:
               if (!closeEnoughTo(castle)) return MoveMoreTowards(castle);
               mystate = DragonState.OpeningCastleDoor;
         case DragonState.OpeningCastleDoor:
               if (!castledoor.FullyOpen()) return Wait();
               mystate = DragonState.PuttingWholeFreakinCastleOnFire;
         case DragonState.PuttingWholeFreakinCastleOnFire:
               if (!EverythingBurning(castle)) return ThrowMoreFire();

so the coroutine approach basically allows us to store the "state" of an 
object on the callstack, instead of having to remember it "myself" from 
one frame to the next.  Granted the state machine example here could 
probably be written a bit more elegantly, and I am not showing the code 
inside the methods that the coroutine variant is calling, but I hope 
this example illustrate the convenience coroutines bring to people who 
would otherwise have to resort to a state machine to deal with their 
asynchronous programming problems.

Please realize I'm not saying that the current implementation of MonoCo 
is good (or bad). I'm just looking at it from a user's point of view. I 
know next to nothing about the internals of the VM.

Other elements that are very important to our game development 
activities, are being able to use the visual studio debugger on a mono 
process. I just cannot wait until that beta starts.  We type all our 
code in Visual Studio. I hope I'm not stepping on any toes here, but I 
feel it's just such an enormous productivity enhancement, it feels quite 
silly to write anything more than a hello world program in a text editor 
that has no understanding of the programming language you're typing into 
it.  We love visual studio, and I cannot wait until I can use its 
debugging facilities to replace my printf based debugging.

We're extremely happy that the Unity3D folks (an engine I can highly 
recommend), chose Mono as their scripting provider, as it allows us to 
run the same code on the clientside and the serverside of our game.  
(pathfinding, collision detection,  etc etc).   having it in the same 
languages saves a lot of dev time, and bug tracking time.

Phew, this turned into a long post.  Anyway, this was a message from a 
very big Mono fan. Thanks to all the people that have made it to what it 
is today, Mono is one of the best things that have happened to our game 
development process in quite some time.

Bye, Lucas

PS Excuse a possible doublepost. Email weirdness in full swing.

-- Game Development Blog: http://lucasmeijer.com/blog

More information about the Mono-devel-list mailing list