Ed Angelis Ribeiro
Ed Angelis Ribeiro

Reputation: 109

Wait for all requests to continue

Please, can this code be done async? I have problems because all requests must be terminated before the code can continue, I saw something about how wait an isolated request, but then i couldn't use the loop, I've been trying to solve this for a while, if anyone can help me it would e great.

StartCoroutine(GetTexture());    

IEnumerator GetTexture() {

    for (int i = 0; i < 10; i++)
    {
        string url = string.Format("https://galinha.webhost.com/img/{0}.jpg", words[i]);
        UnityWebRequest www = UnityWebRequestTexture.GetTexture(url);
        yield return www.SendWebRequest();

        if(www.isNetworkError || www.isHttpError) {
            selectionSprites.Add(sprites[i]);
        }
        else {
            Texture2D myTexture = ((DownloadHandlerTexture)www.downloadHandler).texture;
            Sprite spriteFromWeb = Sprite.Create(myTexture, new Rect(0, 0, myTexture.width, myTexture.height), new Vector2(0, 0));
            selectionSprites.Add(spriteFromWeb);  
        }

    }//for

Upvotes: 0

Views: 4371

Answers (2)

derHugo
derHugo

Reputation: 90649

can this code be done async?

note that async is a keyword and a bit misleading here. Ofcourse you can do web requests etc async but the code would be completely different since most of the Unity API can't be used on threads...

Coroutines are never async but still run in the main thread like if they were temporary Update methods. In fact the MoveNext call for Coroutines is done right after the Update.


Waiting for multiple WebRequests parallel

So I guess what you rather ment is

can these requests be awaited parallel?

Esiest solution I can imagine where you wouldn't have to change your code structure too much would be to store all UnityWebRequestAsyncOperations (what is returned by SendWebRequest in an array and yield until all of them are isDone like e.g.

using System.Linq;

...

IEnumerator GetTexture() 
{
    var requests = new List<UnityWebRequestAsyncOperation>(10);

    // Start all requests
    for (var i = 0; i < 10; i++)
    {
        var url = string.Format("https://galinha.webhost.com/img/{0}.jpg", words[i]);
        var www = UnityWebRequestTexture.GetTexture(url);

        // starts the request but doesn't wait for it for now
        requests.Add(www.SendWebRequest());
    }

    // Now wait for all requests parallel
    yield return new WaitUntil(() => AllRequestsDone(requests));

    // Now evaluate all results
    HandleAllRequestsWhenFinished(requests);

    foreach(var request in requests)
    {
        request.Dispose();
    }
}

private void HandleAllRequestsWhenFinished(List<UnityWebRequestAsyncOperation> requests)
{
    for(var i = 0; i < 10; i++)
    {
        var www = requests[i].webRequest;
        if(www.isNetworkError || www.isHttpError) 
        {
            selectionSprites.Add(sprites[i]);
        }
        else 
        {
            Texture2D myTexture = ((DownloadHandlerTexture)www.downloadHandler).texture;
            Sprite spriteFromWeb = Sprite.Create(myTexture, new Rect(0, 0, myTexture.width, myTexture.height), new Vector2(0, 0));
            selectionSprites.Add(spriteFromWeb);  
        }
    }
}

private bool AllRequestsDone(List<UnityWebRequestAsyncOperation> requests)
{
    // A little Linq magic
    // returns true if All requests are done
    return requests.All(r => r.isDone);

    // Ofcourse you could do the same using a loop
    //foreach(var r in requests)
    //{
    //    if(!r.isDone) return false;
    //}
    //return true;
} 

For completeness: WaitUntil and Linq All

Upvotes: 7

Ed Angelis Ribeiro
Ed Angelis Ribeiro

Reputation: 109

I Tried put the StarCoroutine into the loop for, but dont work, it even worked on the one hand, cause the program waited untill the last Startcoroutine, but dont waited the last to complete, and also it ran all Webrequest kinda at the same time, not respecting the order in the end. I could have tried to put the Inumerator into the loop together with the Coroutine, to see how it would behave, but i dont.

I also tried the script above, using System.Linq and UnityWebRequestAsyncOperation[], but it exhibited similar behavior that my origin script, I still couldn't get that the program wait for all the coroutine.

In the end, i just did the request in a previous scene and load in a static list to use when it was necessary, that way I think the game even works more fluid.

Thanks for all help.

Upvotes: 0

Related Questions