Link to home
Start Free TrialLog in
Avatar of deleyd
deleydFlag 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.)
Avatar of Eduard Ghergu
Eduard Ghergu
Flag of Romania image

Hi,

Why are you calling ThreadPool.SetMaxThreads(8, 8)?
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 -User generated image-saige-
Avatar of 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().
Avatar of 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.
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
Avatar of deleyd
deleyd
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial