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!