Douglas Gaskell
Douglas Gaskell

Reputation: 10020

C# starting tasks to run async methods

I'm trying to create Tasks that will run async methods, the issue is that I cannot await the Action parameter in the Task's constructor, or the the parameters for Task.Factory.StartNew.

Depending on how I'm instantiating my tasks, I have different issues. I have provided seven examples with comments on the issues each creates below.

Example Code: (seven examples of task creation)

    private ConcurrentDictionary<int, Task> Tasks { get; set; }
    private bool active = true;

    private async Task StartTasks()
    {
        int numTasks = 5;

        for(int i = 0; i < numTasks; i++)
        {
            //Task status is almost instantly "RanTocompletion" while work is still being done
            Task task = new Task<Task>(DoWork, "someinfo", TaskCreationOptions.LongRunning);
            task.Start();

            //Cannot await method group
            Task task = new Task(await DoWork, "someinfo", TaskCreationOptions.LongRunning);
            task.Start();

            //Task status is almost instantly "RanTocompletion" while work is still being done
            Task task = new Task(async (object state) => await DoWork(state), "someinfo", TaskCreationOptions.LongRunning);
            task.Start();

            //Throws a "Start may not be called on a promise-style task." Exception
            Task task = new Task<Task>(DoWork, "someinfo", TaskCreationOptions.LongRunning).Unwrap();
            task.Start();

            //Task starts doing work after Start() is called, then throws a "Start may not be called on a promise-style task." Exception
            Task task = new Task(DoWork, "someinfo", TaskCreationOptions.LongRunning);
            task.Start();

            //Task starts doing work, but status is "WaitingForActivation
            Task task = Task.Factory.StartNew(DoWork, "someinfo", TaskCreationOptions.LongRunning);

            //Throws a "Start may not be called on a promise-style task." Exception
            Task task = Task.Factory.StartNew(DoWork, "someinfo", TaskCreationOptions.LongRunning).Unwrap();

            //For checking up on tasks as work is done
            Tasks.TryAdd(task.Id, Task);
        }
    }

    private async Task DoWork(object state)
    {
        while (active)
        {
            await MakeHttpRequest();
            await DoSomethingCpuBound();
            //..etc
        }
        //do any cleanup and return
    }

I cannot use Task.Run() since that does not provide TaskCreationOptions. These tasks will run for literal days.

How can I start a task to await an async action?

Upvotes: 0

Views: 3840

Answers (1)

Stephen Cleary
Stephen Cleary

Reputation: 456322

How can I start a task to await an async action?

In the TAP, tasks are returned "hot". So you literally just need to call the method and keep the task it returns:

private ConcurrentDictionary<int, Task> Tasks { get; set; }
private async Task StartTasks()
{
  for(int i = 0; i < 5; i++)
  {
    Task task = DoWork(null);
    Tasks.TryAdd(task.Id, task);
  }
}

I cannot use Task.Run() since that does not provide TaskCreationOptions. These tasks will run for literal days.

You don't need TaskCreationOptions. The LongRunning flag is just a hint, and the thread pool will recover within a couple of seconds even if you don't specify that hint. But that doesn't even matter, because your work is asynchronous so it doesn't need to run on the thread pool in the first place.

Upvotes: 2

Related Questions