Search code examples
c#async-awaittask-parallel-library

Is there a way to run an async method as a LongRunning task?


I'm looking to run an async method as a long-running thread, as in using the TaskCreationOptions.LongRunning option. In my testing I'm considering the thread as running as a "long-running" thread if it is not a thread-pool thread (i.e. I expect that Thread.CurrentThread.IsThreadPoolThread will be false).

This is my attempt:

var task = Task.Factory.StartNew(DoWorkAsync,
            CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default);
task.Unwrap().Wait();

static async Task DoWorkAsync()
{
    Console.WriteLine("IsThreadPoolThread: " + Thread.CurrentThread.IsThreadPoolThread);
    await Task.Delay(100);
    Console.WriteLine("IsThreadPoolThread: " + Thread.CurrentThread.IsThreadPoolThread);
}

The output of this is:

IsThreadPoolThread: False
IsThreadPoolThread: True

meaning that after the first await the thread is no longer like a long-running thread.

This outcome intuitively makes sense as I'm passing the TaskFactory.StartNew() method a Func<Task> where the generic type of Task is simply interpreted as the result type of the Task that is created by TaskFactory.StartNew(), so I end up getting a Task<Task> which completes once the async method returns its Task, i.e. once the first await statement is encountered.

Is there a way to have the entire execution of the async method run as a long-running thread, i.e. to have all continuations run as non-thread-pool threads?


Solution

  • Thanks for all the helpful comments on this question!

    As @Theodor Zoulias pointed out, this is possible to do by using a custom TaskScheduler.

    However, the best answer to "how do you run an async method as a LongRunning task?" is probably "You don't". As @Charlieface pointed out the LongRunning task option only makes sense for long-running blocking threads. The use of coroutines (achieved via the async/await construct) defeats the LongRunning option because whenever an await is encountered the relevant thread will be released and returned to the thread pool.