Unity Networking – Async vs Coroutine

Few days ago I was writing some replay on one of the forums regarding Unity networking and had to provide 2 examples of network access with native Unity Coroutine functionality and basic C# functionality which also work great inside the Unity, that thread was killed by moderators for the unrelated spam, however I still have Unity project as example, so ill re-share it here.

First of all lets have a look at the difference of Async and Coroutines:

Coroutines: in simple words could be explained as reference to the execution point where process keep coming back to check if condition was satisfied.
Example:
Lets assume we have to register new user in our server side database from Unity application.
Then we will have to:

  • Gather data from input fields
  • Validate data
  • Build up GET request URL or POST object
  • Send data to the server
  • Wait for server response

Where at the server side we will also have to perform several steps, like:

  • Capture client request
  • Validate input
  • Check database if user not already registered
  • Register user
  • Buildup response to client
  • Respond

So we talking about good few seconds delay between send request to server and receive response from it.
In case of Coroutines, process will send the data to server and make reference at that point, it would continue execution of the following code without blocking state, however it will keep coming back to that reference mark to check if execution of coroutine was complete and condition was satisfied. In other words execution process jumping from currently executed code to coroutine point and back, until coroutine will be completed.
Asynchronous: is on other had completely separate thread, which runs on background individually and usually notify when it is complete through call back method.

Now lets look on the Actual Unity implementation of Coroutines:

Execution class:

public class GUI : MonoBehaviour {

    //skipped

    void Start () {
        coroutineUrl =  "https://dl.dropboxusercontent.com/u/15715229/Habra/coroutine.html";
       //skipped
    }

    void OnGUI()
    {
        //skipped
        if(GUILayout.Button("Coroutine Example"))
        {
             //skipped
             StartCoroutine(CoroutineExample.CoroutineWebRequest(coroutineUrl));
             //skipped
        }
        //skipped
    }
}

We just hit the button and it call CoroutineExample.CoroutineWebRequest, lets see what is going on there
Process Class:

public class CoroutineExample : MonoBehaviour {

    private static string serverResponse;

    public static IEnumerator CoroutineWebRequest(string url)
    {
        WWW web = new WWW(url);
        while (!web.isDone)
        {
            yield return null;
        }

        if (web.error != null)
        {
            serverResponse = "Server Error: " + web.error;
        }
        else
        {
            serverResponse = "Coroutine Server Say: " + web.text;
        }
    }
}

As you see it is very simple, it will yield – or wait by executing another code until process is done and while statement is complete and then continue execution from that point.

Now lets have a look at the Async example:

I will start from Async worker – it is the actual class where we perform web access:

using System.Net;

public class AsyncWorker {

	public string DoWork(string url)
    {
        WebClient web = new WebClient();
        string result = web.DownloadString(url);
        return "Async Server Say: "+result;
    }
}

Because we accessing web in asynchronous way we are blocked from using Unity native WWW class. Unity allow to use WWW class only from main thread however Async process is parallel thread. (Keep in mind that there are good few classes which unity doesn’t allow to run in parallel thread)
It is not a problem as we can use C# native WebClient Class which from my point of view even better than Unity WWW

Now lets look how we start Async request from GUI button click:

public class GUI : MonoBehaviour {

	//Skipped

	void Start () {
        asyncUrl =      "https://dl.dropboxusercontent.com/u/15715229/Habra/async.html";
		//Skipped
	}
	
    void OnGUI()
    {
		//Skipped
		if (GUILayout.Button("Async Example"))
		{
			//Skipped
			AsyncExample.StartAsync(asyncUrl);
			//Skipped
		}
		//Skipped
    }
	//Skipped
}

And finally lets have a look on what is going on in the misterious AsyncExample.StartAsync method:

using System;
using System.Runtime.Remoting.Messaging;
using UnityEngine;

public class AsyncExample : MonoBehaviour {

    private static string serverResponse;
    private delegate string myCallBackDelegate(string url);

    public AsyncExample()
    {
        serverResponse = ""; 
    }
	
    public static void StartAsync(string url)
    {
        myCallBackDelegate deleg = new myCallBackDelegate(new AsyncWorker().DoWork);
        deleg.BeginInvoke(url, new AsyncCallback(onServerResponse), null);
    }


    private static void onServerResponse(IAsyncResult result)
    {
        AsyncResult res = (AsyncResult)result;
        myCallBackDelegate deleg = (myCallBackDelegate)res.AsyncDelegate;
        serverResponse = deleg.EndInvoke(result);        
    }
}

It is exactly the same Async process which I already describe in one of my previous post
It just create delegate, BegineEnvoke it by passing input parameters which is URL in our case and set CallBack method where Server response supposed to fall when completed for extraction of an actual response.
That is it!

Full Unity project can be downloaded from my:

C# Async Calculations

This is example of Async calculation implementation in C# which works nearly in the same way as recently published post related to Java Async Programming

Task:

Execute parallel task on background and retrieve result of calculations once task is complete.

Implementation:

Lets start from our worker which will perform heavy calculations

using System;
using System.Threading;

namespace AsyncCalculations
{
    class AsyncWorker
    {
        public string performLongAndHeavyCalculation(int dig1, int dig2)
        {
            Console.WriteLine("Worker: Starting job");
            int sum = dig1 + dig2;
            Thread.Sleep(3000);
            Console.WriteLine("Worker: Job Complete");
            return "Result of heavy calculation is: "+sum;
        }
    }
}

Well calculations are not that heavy 🙂
but 3 seconds of sleep could represent request to the server side database. There is nothing really to talk about, everything simple and straightforward.

Now lets have a look at our main thread – async caller:

using System;
using System.Runtime.Remoting.Messaging;
using System.Threading;

namespace AsyncCalculations
{
    class AsyncCaller
    {
        public static void Main(string[] args)
        {
            new AsyncCaller();
        }

        //define delegate
        private delegate string MyAsyncDelegate(int dig1, int dig2);

        private bool gotResponse;
        private string workerResponse;
        public AsyncCaller()
        {
            gotResponse = false;
            int num1 = 10;
            int num2 = 30;

            Console.WriteLine("Main Thread: Start");
            Console.WriteLine("Main Thread: launching worker");
            //create delegate
            MyAsyncDelegate myDelegate = new MyAsyncDelegate(new AsyncWorker().performLongAndHeavyCalculation);
            //execute async task
            myDelegate.BeginInvoke(num1, num2, new AsyncCallback(onCallBack), null);
            Console.WriteLine("Main Thread: worker executed");

            //wait for a response
            while(!gotResponse)
            {
                Console.WriteLine("Wating for worker to complete his job....");
                Thread.Sleep(500);
            }
            //Display response result
            Console.WriteLine("Main Thread: Worker says: "+workerResponse);
            Console.WriteLine("Main Thread: Finished");

            Console.WriteLine("Press any key to exit...");
            Console.ReadKey();
        }

        public void onCallBack(IAsyncResult result)
        {
            //recats result
            AsyncResult res = (AsyncResult)result;
            //retrieve delegate
            MyAsyncDelegate myDeleg = (MyAsyncDelegate)res.AsyncDelegate;
            //get response and set it to local variable
            workerResponse = myDeleg.EndInvoke(result);
            gotResponse = true;
        }
    }
}

Now lets talk about code:
1) Delegate – private delegate string MyAsyncDelegate(int dig1, int dig2);
the main thing to know about delegate is that delegate have to match to the method signature
in our case string is return type, dig1, dig2 – two integers as input params
2) Delegate Creation – MyAsyncDelegate myDelegate = new MyAsyncDelegate(new AsyncWorker().performLongAndHeavyCalculation);
if you will check “AsyncWorker” class, you would notice that string performLongAndHeavyCalculation(int, int) match to our delegate signature.
3) Executing Async with BeginInvoke – myDelegate.BeginInvoke(num1, num2, new AsyncCallback(onCallBack), null);
Async Execution consist of 3 params:

  • Method input – in our case num1 and num2 which are dig1 and dig2
  • Call back response – method which will be invoked when result is ready
  • object – in our case it is null

4) On Call back event we getting delegate reference back
5) and getting result value by calling myDeleg.EndInvoke(result);

as simple as that 🙂

here is console output:

Main Thread: Start
Main Thread: launching worker
Main Thread: worker executed
Wating for worker to complete his job....
Worker: Starting job
Wating for worker to complete his job....
Wating for worker to complete his job....
Wating for worker to complete his job....
Wating for worker to complete his job....
Wating for worker to complete his job....
Wating for worker to complete his job....
Worker: Job Complete
Main Thread: Worker says: Result of heavy calculation is: 40
Main Thread: Finished
Press any key to exit...

You can download Visual Studio Project from my: