//-----------------------------------------------------------------------------------
// Creates and begins execution of a new spooling task. Executes synchronously,
// and by the time this API has returned all of the results have been produced.
//
// Arguments:
// groupState - values for inter-task communication
// partitions - the producer enumerators
// channels - the producer-consumer channels
// taskScheduler - the task manager on which to execute
//
internal static void SpoolStopAndGo <TInputOutput, TIgnoreKey>(
QueryTaskGroupState groupState, PartitionedStream <TInputOutput, TIgnoreKey> partitions,
SynchronousChannel <TInputOutput>[] channels, TaskScheduler taskScheduler)
{
Debug.Assert(partitions.PartitionCount == channels.Length);
Debug.Assert(groupState != null);
// Ensure all tasks in this query are parented under a common root.
Task rootTask = new Task(
() =>
{
int maxToRunInParallel = partitions.PartitionCount - 1;
// A stop-and-go merge uses the current thread for one task and then blocks before
// returning to the caller, until all results have been accumulated. We do this by
// running the last partition on the calling thread.
for (int i = 0; i < maxToRunInParallel; i++)
{
TraceHelpers.TraceInfo("SpoolingTask::Spool: Running partition[{0}] asynchronously", i);
QueryTask asyncTask = new StopAndGoSpoolingTask <TInputOutput, TIgnoreKey>(i, groupState, partitions[i], channels[i]);
asyncTask.RunAsynchronously(taskScheduler);
}
TraceHelpers.TraceInfo("SpoolingTask::Spool: Running partition[{0}] synchronously", maxToRunInParallel);
// Run one task synchronously on the current thread.
QueryTask syncTask = new StopAndGoSpoolingTask <TInputOutput, TIgnoreKey>(
maxToRunInParallel, groupState, partitions[maxToRunInParallel], channels[maxToRunInParallel]);
syncTask.RunSynchronously(taskScheduler);
});
// Begin the query on the calling thread.
groupState.QueryBegin(rootTask);
// We don't want to return until the task is finished. Run it on the calling thread.
rootTask.RunSynchronously(taskScheduler);
// Wait for the query to complete, propagate exceptions, and so on.
// For pipelined queries, this step happens in the async enumerator.
groupState.QueryEnd(false);
}