-2

Can anyone explain to me why second Working! shows after Done ?

Stating
Doing Work
Working!
Done
Working!
Work completed

Second question why can't I just do like below to get Task result:

Task result = await LongOperation();

And last question is what would be the reason to use Task.Run on behalf with await/async for instance in my code? Where could it be used or is it not good to use it?

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Starting");
        var worker = new Worker();
        worker.DoWork();
        Console.WriteLine("Done");
        Console.ReadKey();
    }
}

public class Worker
{
    public async void DoWork()
    {
        Console.WriteLine("Doing work");

        await LongOperation();
        await LongOperation();

        Console.WriteLine("Work completed");
    }

    private async Task LongOperation()
    {
        Console.WriteLine("Working!");
        await Task.Delay(200);
    }
}
CDspace
  • 2,639
  • 18
  • 30
  • 36
Dino
  • 79
  • 9
  • 1
    1. Because you call `LongOperation` twice. 2. Because that's not how `await` works. 3. To call a synchronous operation asynchronously. (In the future, please try to keep it to one question per post.) – BJ Myers May 19 '17 at 22:16
  • 3
    Please see [How to Ask](http://stackoverflow.com/help/how-to-ask). You should avoid asking multiple questions in the same thread. Also, it would make it a lot easier for us to understand if you provided some context as to what you're asking (especially in the 1st question) means. – stelioslogothetis May 19 '17 at 22:17

4 Answers4

0

This is because you have declared DoWork() asynchronous with a return type of void. This makes it a "fire and forget" method that is running asynchronously. If you have DoWork() return a Task instead of void, you can await it, and that would ensure your "Done" message would occur after DoWork() has completed execution.

Additionally, await unwraps the task result, so you cannot await it and get the value at the same time. If you wish to use the Task result directly, do not await it.

There is no specific area in the code you specified where you should be using Task.Run().

Technetium
  • 5,902
  • 2
  • 43
  • 54
0

There reason "Done!" appears sooner than you expect is because you do not have await in front of worker.DoWork(); (and DoWork needs to return a Task to be able to use await). So what happens is DoWork() returns immediately with execution deferred to another thread, and immediately goes to next line which is the console write "done".

Regarding Task result = await LongOperation();, await takes in as parameter awaitable object (i.e. Task), examines its .Result property on your behalf, extracts the result and returns it. So you either drop await to get the task instance, or you put await to wait for task completion and extracting the actual return value of the call.

There are a few reasons to use Task.Run or through task factory, one example being passing lambda function for execution (possibly with closure). I would refer to MSDN library on TPL for detailed dive.

LB2
  • 4,802
  • 19
  • 35
0
  1. Working shows after Done! because in your static void Main you aren't waiting for worker.DoWork(); to complete, so the program executes the next line. You should change DoWork method like this:

    public async Task DoWork()
    {
        //
    }
    

And change the call to it like this:

worker.DoWork().GetAwaiter().GetResult();
  1. You can't because using await your LongOperation will not return a Task. For example if you had a signature like this, when you use await you unwrap the result:

    public Task<int> GiveANumberAsync()
    {
        return Task.FromResult(12);
    }
    
    int result = await GiveANumberAsync();
    
  2. For this question I think I can't explain better than Stephen in this answer, where he says:

Use Task.Run to call CPU-bound methods.

Community
  • 1
  • 1
Francesco Bonizzi
  • 5,142
  • 6
  • 49
  • 88
0

Taking your questions one by one:

  1. In Main, you do not await DoWork. This means that it is invoked, and then execution of the code in the Main continues, without waiting for DoWork to finish. As such, "Done" is printed to the console right away before the second "Working".
  2. This isn't what the await keyword does. From the documentation:

The await operator is applied to a task in an asynchronous method to suspend the execution of the method until the awaited task completes. The task represents ongoing work. [...] The task to which the await operator is applied typically is the return value from a call to a method that implements the Task-Based Asynchronous Pattern. Examples include values of type Task or Task<TResult>.

Effectively, in order to await a method, it must have return type Task<T>, where T is the actual type of what you return in your code. Your method LongOperation doesn't actually return anything in this example.

  1. Task.Run is used to run any method or block of code as a Task. It can be fired and forgotten (Task.Run([something];), or awaited like any other task (await Task.Run([something]);. See the documentation for it here, though I'm not sure it will be much help. User Stephen Cleary explained it well in this answer, along with some other pertinent information.
Community
  • 1
  • 1
stelioslogothetis
  • 9,371
  • 3
  • 28
  • 53