According to the Microsoft TPL documentation I read (link) calling the Task.Wait() method will block the current thread until that task finishes (or cancels, or faults). But it also said that if the task in question hadn't started yet, the Wait method will attempt to run it on its own thread by asking the scheduler to reassign it, thus reducing the amount of wastage due to blocking.
I've got a system in which tasks (once running) begin by collecting data by starting other tasks and waiting on their results. These other tasks in turn begin by collecting data from yet other tasks and-so-on-and-so-fort, potentially a few hundred layers deep. I really don't want umpteen tasks blocking and waiting for the one task at the end to finally finish.
However when I tried this out in a test console app, Task.Wait() doesn't seem to start anything at all.
What are the correct incantations for building a sequence of tasks that must all wait on each other with a minimum of wasted cycles? It's sort of like ContinueWith, except starting with the last task in the series...
using System;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
var source = new CancellationTokenSource();
var token = source.Token;
// Create a non-running task.
var task = new Task<string[]>(() => InternalCompute(token), token);
// Isn't this supposed to start the task?
task.Wait(CancellationToken.None);
// I realise this code now won't run until the task finishes,
// it's here for when I use task.Start() instead of task.Wait().
Console.WriteLine("Press any key to cancel the process.");
Console.ReadKey(true);
source.Cancel();
Console.WriteLine("Source cancelled...");
Console.WriteLine("Press any key to quit.");
Console.ReadKey(true);
}
private static string[] InternalCompute(CancellationToken token)
{
string[] data;
try
{
data = Compute(token);
}
catch (TaskCanceledException ex)
{
return null;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return new[] { ex.Message };
}
Console.WriteLine("Post-processor starting.");
for (int i = 0; i < data.Length; i++)
if (data[i] is null)
Console.WriteLine($"Null data at {i}.");
else
Console.WriteLine($"Valid data at {i}.");
Console.WriteLine("Post-processor completed.");
return data;
}
/// <summary>
/// This method stands in for an abstract one to be implemented by plug-in developers.
/// </summary>
private static string[] Compute(CancellationToken token)
{
var data = new string[10];
for (int i = 0; i < data.Length; i++)
{
token.ThrowIfCancellationRequested();
Thread.Sleep(250);
data[i] = i.ToString();
Console.WriteLine($"Computing item {i + 1}...");
}
return data;
}
}
}