Avatar of deleyd
deleyd
Flag for United States of America asked on

Can a Task.Run().Wait() task end up being "inlined"?

Is it possible for the following task to be "inlined" and run on the current thread when the t.Wait(); is encountered?
Task t = Task.Run(() => MyMethod());
t.Wait();

Open in new window

If so, can you provide some example code that does this?

(I've tried setting ThreadPool.SetMaxThreads(8, 8); (This succeeds. My computer has 8 CPUs.) and then launching a dozen tasks via Task.Run() to try and fill up the ThreadPool so my Task t = Task.Run() gets queued but not run. However, I have not been able to get t.Wait(); to "inline to inline the task. So far it just always waits I assume for a free ThreadPool thread to become available.)
.NET ProgrammingC#

Avatar of undefined
Last Comment
deleyd

8/22/2022 - Mon
Eduard Ghergu

Hi,

Why are you calling ThreadPool.SetMaxThreads(8, 8)?
it_saige

Short answer is no.

You cannot inline the wait call in that fashion since the Wait method returns a bool and the Run method returns a Task.

If you need to wait for all of your tasks to finish before returning the results, then you should add your tasks to a list and use Task.WaitAll; e.g. -
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace EE_Q29170256
{
    class Program
    {
        static void Main(string[] args)
        {
            var tasks = new List<Task<int>>(from i in Enumerable.Range(0, 5) select Task.Run(() => 
            {
                Task.Delay(1000);
                return i;
            }));

            Task.WaitAll(tasks.ToArray());
            foreach(var task in tasks)
            {
                Console.WriteLine($"Task {task.Id} resulted in {task.Result}");
            }
            Console.ReadLine();
        }
    }
}

Open in new window

Which produces the following output -Capture.PNG-saige-
deleyd

ASKER
My goal is to get the task to be "inlined" by the t.Wait(); statement.
Setting Max Threads to a low value was part of my attempt to accomplish this goal.

The Microsoft documentation for Task.Wait() states:

Wait is a synchronization method that causes the calling thread to wait until the current task has completed. If the current task has not started execution, the Wait method attempts to remove the task from the scheduler and execute it inline on the current thread. If it is unable to do that, or if the current task has already started execution, it blocks the calling thread until the task completes. For more information, see Task.Wait and "Inlining" in the Parallel Programming with .NET blog. https://devblogs.microsoft.com/pfxteam/task-wait-and-inlining/

I can accomplish this by doing:
Task t = MyMethod();
t.Wait();

Open in new window

I'm trying to determine if inlining can also happen if I first call Task.Run().
Experts Exchange has (a) saved my job multiple times, (b) saved me hours, days, and even weeks of work, and often (c) makes me look like a superhero! This place is MAGIC!
Walt Forbes
deleyd

ASKER
Here is my current attempt to get a task to inline:
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace ThreadConsoleApp6
{
    class Program
    {
        static void Main(string[] args)
        {
            ShowMaxThreads();
            ShowAvailableThreads();
            bool stat = ThreadPool.SetMaxThreads(8, 8);
            ShowAvailableThreads();

            var tasks = new List<Task>();
            for (int i = 0; i < 8; ++i)
            {
                tasks.Add(Task.Run(() => Wait5Seconds()));
            }
            Thread.Sleep(1000);

            ShowAvailableThreads();
            Thread thread = Thread.CurrentThread;
            int threadId = thread.ManagedThreadId;
            Console.WriteLine("Main Thread:  {0:N0}", threadId);
            Console.WriteLine("Main thread is available. Let's run AnotherTask()");

            Task t = Task.Run(() => AnotherTask());
            t.Wait();  // We're waiting. Why does it not inline task and run it on main thread?

            Task.WaitAll(tasks.ToArray());
            Console.WriteLine("Press any key");
            Console.ReadKey();
        }

        static private void AnotherTask()
        {
            Thread thread = Thread.CurrentThread;
            int threadId = thread.ManagedThreadId;
            Console.WriteLine("Another Task Thread:  {0:N0}", threadId);
        }

        static void Wait5Seconds()
        {
            Thread.Sleep(5000);
        }

        static private void ShowMaxThreads()
        {
            int workerThreads;
            int portThreads;
            ThreadPool.GetMaxThreads(out workerThreads, out portThreads);
            Console.WriteLine("\nMaximum worker threads: \t{0}\nMaximum completion port threads: {1}", workerThreads, portThreads);
        }

        static private void ShowAvailableThreads()
        {
            int workerThreads;
            int portThreads;
            ThreadPool.GetAvailableThreads(out workerThreads, out portThreads);
            Console.WriteLine("\nAvailable worker threads: \t{0}\nAvailable completion port threads: {1}\n", workerThreads, portThreads);
        }
    }
}

Open in new window

I set max threads to 8 because that's the minimum I can for my machine. I then spin off 8 tasks so there are no more available ThreadPool threads. I then try to get AnotherTask() to be inlined, but it insists on waiting instead.
Eduard Ghergu

Hi,
There is no warranty to have the inline performed if Task.Run() is invoked as long as it just enqueue the execution of the specified delegate. In the end, what you're trying to obtain?
ASKER CERTIFIED SOLUTION
deleyd

THIS SOLUTION ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
GET A PERSONALIZED SOLUTION
Ask your own question & get feedback from real experts
Find out why thousands trust the EE community with their toughest problems.