简体   繁体   中英

Declaring a Task Property and awaiting it

I'm stuck in something I thought so simple that it drives me out of myself.

I need to declare a Task in some point and run it later , I thought of:

Task T1 { get; set; }

public async Task CreateAndAwaitAsync()
{
    T1 = new Task(() => {
        // time consuming work like:
        System.Threading.Thread.Sleep(1000);
    }

    await T1;
}

Of course the body of the lambda AND the method are just for the sake of this example (as I said I need to run it later), but no matter what, with await T1 I just cannot make it into the lambda! What am I missing?? I feel stupid because I have been using the async-await paradigm for quite the few years already that I didn't even imagine this wouldn't work!

I thought it can be answered in comment but better to provide more info.

await means "wait for this task to complete, then do the rest stuff". Task from your example is not started. await will not start it for you, so the whole method will just stuck at await until you start the task.

Even with your current code, if you later do T1.Start() - it will run your lambda and after it is completed - your task returned by CreateAndAwaitAsync will also complete.

Otherwise - either start task right when creating it ( Task.Run ) or just return Task directly without any async\\await:

public Task CreateAndAwaitAsync()
{
    T1 = new Task(() => {
        // time consuming work like:
        System.Threading.Thread.Sleep(1000);
    }
    // if you need to start it somewhere, do T1.Start();
    return T1;
}

Like @Evk said, you need to call T1.Start()

public async Task CreateAndAwaitAsync()
    {
        T1 = new Task(() =>
        {
            // time consuming work like:
            System.Threading.Thread.Sleep(1000);
        });

        T1.Start();
        await T1;
    }

You are not starting the task.

Example:

public async Task DoSomething()
{
    await Task.Run(() => SomeMethod());
}

You're only creating a Task but it is not running even with await here. Try to Start() it, or you can assign T1 = Task.Run(your => lambda) and then it should work when you awaiting it

Unless you are doing CPU-bound work you almost never need to call Task.Run but can just use async/await like:

  public async Task DelayMe()
  {
    await Task.Delay(1000);
    await MoreAsyncThings();
  }

  Task T1 { get; set; }

  public async Task CreateAndAwaitAsync()
  {
    T1 = DelayMe();
    await T1;
  }

Update:

To store code for later execution I would propose to simple use a lambda like:

Func<Task> SomeWorkFactory()
{
  return async () => 
  { 
    await AsyncStuff(); 
    // More Stuff 
  };
}

var deferedWork = SomeWorkFactory();

// later somewhere else

await deferedWork(); 

So basically calling "SomeWorkFactory" creates the work package but only calling the Func executes it and also returns an awaitable Task.

Maybe relevant:

If you provide methods which do CPU-bound work (like calculating something as opposed to waiting for a callback) you should not offer an async signature at all but leave the execution mode to the caller. Mainly because asynchronism and concurrency are different concepts. Mads Torgersen gave some insights on this here: https://channel9.msdn.com/Events/TechEd/NorthAmerica/2014/DEV-B362 and calls it "library methods should not lie" (From minute 42)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM