Abhijeet
Abhijeet

Reputation: 13856

Async Method does not return control back to caller

Control is returned back to main method, before UploadToServer executes completely. Should I remove Task.Run() from UploadToServer or do a WaitAll explicitly?

public class Uploader
{
    async public Task<int> Upload(int i)
    {
        int incremented = 0;
        var t = UploadToServer(i);
        if (t != null)
        {
            incremented = await t;
        }
        return incremented;
    }

    async private Task<int> UploadToServer(int i)
    {
        int incremented = 0;
        await Task.Run(() =>
        {
            //Console.ReadLine();
            //Actual upload operation
            incremented = i + 1;
        });
        return incremented;
    }
}


class Program
{
    static void Main(string[] args)
    {
        Uploader upl = new Uploader();
        var res = upl.Upload(10).Result;
    }
}

Upvotes: 2

Views: 2004

Answers (2)

faby
faby

Reputation: 7558

try in this way

private Task<int> UploadToServer(int i)
{
    int incremented = 0;
    return Task.Run(() =>
    {
        //Console.ReadLine();
        //Actual upload operation
        return incremented = i + 1;
    });
}

or in this way

private async Task<int> UploadToServer(int i)
{
     return await Task.Run(() => DoSomething(i)).Wait();
}

private int DoSomething(int i)
{
    //Console.ReadLine();
    //Actual upload operation
     return i+1;
}

Note that these examples aren't particularly useful methods. considers that the background thread should live its own life.

In your case I suppose that maybe you can use some async methods of the HttpClient class of the framework

Example

private async Task<int> GetWebPageHtmlSizeAsync()
{
  var client = new HttpClient();
  var html = await client.GetAsync("http://www.test.com/");
  return html.Length;
}

UPDATE

I've tested this code and it worked

static void Main(string[] args)
{
     Uploader upl = new Uploader();
     var res = upl.Upload(10).Result;
}


public class Uploader 
{
    async public Task<int> Upload(int i)
    {
        int incremented = 0;
        var t = UploadToServer(i);
        if (t != null)
        {
            incremented = await t;
        }
        return incremented;
    }

    private async Task<int> UploadToServer(int i)
    {
        return await Task.Run(() => DoSomething(i));
    }

    private int DoSomething(int i)
    {
        //Console.ReadLine();
        //Actual upload operation
        Thread.Sleep(2000);
        return i + 1;
    }
}

main program waits 2 seconds before receive the right value and the control back.

Have a look at this Should I expose asynchronous wrappers for synchronous methods? article that explains when and how you should use asynchronous methods. In your specific example you aren't getting advantages from task.run. I have only provided to you one working example with your code.

Upvotes: 0

Yuval Itzchakov
Yuval Itzchakov

Reputation: 149538

When you await on async methods, the control is yielded back to the caller. What you're experiencing is proper async behavior.

If you dont want the method to return while the operation is executing, execute it synchronously. If what you're attempting to do is I/O bound work (like upload something to a server), dont use Task.Run, as I/O bound is naturally exposed with async endpoints, eliminating the need for unnecessary threads in the process. Look at HttpClient as an example which exposes a bunch of XXXAsync methods.

Upvotes: 4

Related Questions