5

我將不得不創造出創建多個任務併發軟件上的所有任務(創建的任務和子任務)等,每一個任務可能會產生另外一個任務(這也可能產生另一個任務,.. )。如何不使用TaskCreationOptions.AttachedToParent

我需要調用其發射任務是阻斷法:沒有回來之前,所有的任務和子任務的完成。

我知道有這個TaskCreationOptions.AttachedToParent屬性,但我認爲它不適合:

服務器將具有類似至少8個內核,每個任務將創建2-3子任務,所以如果我設置AttachedToParent選項,我覺得第二個子任務在第一個子任務的三個任務結束之前不會啓動。所以我會在這裏進行有限的多任務處理。

這一進程樹

所以:

enter image description here

我有印象,假如我AttachedToParent屬性,每次我啓動一個線程,B不會E,F,G結束之前完成,所以C會在B完成之前開始,而我將只有3個活動線程,而不是我可以擁有的8個活動線程。

如果我不放置AttachedToParent屬性,A將會非常快速地完成並返回。

所以我怎麼會做,以確保我總是我的8個內核完全使用,如果我不設置這個選項?

+3

不要依賴印象。請在文檔中查看或自己嘗試。 – svick 2012-07-05 11:38:39

回答

2

TaskCreationOptions.AttachedToParent不會阻止其他子從開始,而是防止父任務本身關閉。因此,當E,F和G以AttachedToParent開始時,在所有三個完成之前,B都不會被標記爲結束。所以它應該按照你的意願去做。

source(在接受的答案中)。

2

正如Me.Name提到,AttachedToParent不會根據你的印象不行爲。我認爲在這種情況下這是一個很好的選擇。

但是,如果你不想使用不管什麼原因,你可以等待所有的子任務與Task.WaitAll()完成。儘管這意味着您必須將所有這些內容放在一個集合中。

Task.WaitAll()會阻止當前線程,直到完成所有Task s爲止。如果你不想要,並且你使用的是.Net 4.5,那麼你可以使用Task.WhenAll(),這將返回一個單獨的Task,當所有給定的Tasks完成時,它將結束。

1

你可以你TaskFactory創建選項,如下面的例子:

Task parent = new Task(() => { 
var cts = new CancellationTokenSource(); 
var tf = new TaskFactory<Int32>(cts.Token, 
             TaskCreationOptions.AttachedToParent, 
             TaskContinuationOptions.ExecuteSynchronously, 
TaskScheduler.Default); 

// This tasks creates and starts 3 child tasks 
var childTasks = new[] { 
     tf.StartNew(() => Sum(cts.Token, 10000)), 
     tf.StartNew(() => Sum(cts.Token, 20000)), 
     tf.StartNew(() => Sum(cts.Token, Int32.MaxValue)) // Too big, throws Overflow 
}; 

// If any of the child tasks throw, cancel the rest of them 
for (Int32 task = 0; task <childTasks.Length; task++) 
    childTasks[task].ContinueWith( 
    t => cts.Cancel(), TaskContinuationOptions.OnlyOnFaulted); 

// When all children are done, get the maximum value returned from the 
// non-faulting/canceled tasks. Then pass the maximum value to another 
// task which displays the maximum result 
tf.ContinueWhenAll( 
    childTasks, 
    completedTasks => completedTasks.Where( 
    t => !t.IsFaulted && !t.IsCanceled).Max(t => t.Result), CancellationToken.None) 
    .ContinueWith(t =>Console.WriteLine("The maximum is: " + t.Result), 
     TaskContinuationOptions.ExecuteSynchronously); 
}); 

// When the children are done, show any unhandled exceptions too 
parent.ContinueWith(p => { 
    // I put all this text in a StringBuilder and call Console.WriteLine just once 
    // because this task could execute concurrently with the task above & I don't 
    // want the tasks' output interspersed 
    StringBuildersb = new StringBuilder( 
         "The following exception(s) occurred:" + Environment.NewLine); 

    foreach (var e in p.Exception.Flatten().InnerExceptions) 
     sb.AppendLine(" "+ e.GetType().ToString()); 

    Console.WriteLine(sb.ToString()); 
    }, TaskContinuationOptions.OnlyOnFaulted); 

    // Start the parent Task so it can start its children 
    parent.Start();