Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Task return value, without Task<T> (async/await pattern)

I would like to write the following:

public string GetSomeValue()
{
    //directly return the value of the Method 'DoSomeHeavyWork'...
    var t = DoSomeHeavyWork();
    return t.Result;
}

public Task<string> DoSomeHeavyWork()
{
    return Task.Run(() => {
        // do some long working progress and return a string
        return "Hello World!";
    });
}

As you can see to return the result from the DoSomeHeavyWork() I have used the Task.Result property, which works okay, but according to researches this will block the Thread.

I would like to use the async/await pattern for this but cant seem to find how to do this. If I did the same with async/await with my current knowledge I will always end up with this:

public async Task<string> GetSomeValue()
{
    //directly return the value of the Method 'DoSomeHeavyWork'...
    var t = DoSomeHeavyWork();
    return await t;
}

public Task<string> DoSomeHeavyWork()
{
    return Task.Run(() => {
        // do some long working progress and return a string
        return "Hello World!";
    });
}

This solution doesnt quite fit my needs because I want to return ONLY the string and not a Task<string>, how can this be achieved with async/await?

like image 866
Rand Random Avatar asked May 16 '14 15:05

Rand Random


1 Answers

You can't.

The entire point of async is to run code asynchronously. So the code returns a promise of a future string value, represented in .NET as Task<string>.

Think about it this way: if your code calls public string GetSomeValue(), then by the time the method returns, you already have a string. This is synchronous, by definition.

In your example, you have "heavy" work which I interpret to mean "CPU-bound". In that case, just do the work synchronously:

public string DoSomeHeavyWork()
{
  // do some long working progress and return a string
  return "Hello World!";
}

In general, APIs should not "lie"; if they are synchronous, then they should have a synchronous (non-Task-returning) signature.

Edit: As per your comment, the "heavy" work is a WCF call, which is I/O-bound, not CPU-bound.

In that case, the work is naturally asynchronous. Use asynchronous WCF methods (not Task.Run), and allow the asynchrony to grow through your codebase:

public async Task<string> GetSomeValueAsync()
{
  //directly return the value of the Method 'DoSomeHeavyWork'...
  var t = DoSomeHeavyWorkAsync();
  return await t;
}

public async Task<string> DoSomeHeavyWorkAsync()
{
  // Call asynchronous WCF client.
  await ...;
  return "Hello World!";
}
like image 114
Stephen Cleary Avatar answered Nov 15 '22 08:11

Stephen Cleary