如何在不使用taskcreationopt . attachedtoparent的情况下等待所有任务(创建任务和子任务)

时间:2022-09-17 16:58:29

I will have to create a concurrent software which create several Task, and every Task could generate another task(that could also generate another Task, ...).

我必须创建一个并发软件来创建多个任务,每个任务都可以生成另一个任务(也可以生成另一个任务…)

I need that the call to the method which launch task is blocking: no return BEFORE all task and subtask are completed.

我需要对启动任务阻塞的方法的调用:在完成所有任务和子任务之前不返回。

I know there is this TaskCreationOptions.AttachedToParent property, but I think it will not fit:

我知道有这个TaskCreationOptions。附属物,但我认为不适合:

The server will have something like 8 cores at least, and each task will create 2-3 subtask, so if I set the AttachedToParent option, I've the impression that the second sub-task will not start before the three tasks of the first subtask ends. So I will have a limited multitasking here.

服务器将至少有8个内核,每个任务将创建2-3个子任务,所以如果我设置AttachedToParent选项,我感觉第二个子任务不会在第一个子任务的三个任务结束之前开始。所以我的多任务处理是有限的。

So with this process tree:

通过这个过程树

如何在不使用taskcreationopt . attachedtoparent的情况下等待所有任务(创建任务和子任务)

I've the impression that if I set AttachedToParent property everytime I launch a thread, B will not ends before E,F,G are finished, so C will start before B finish, and I will have only 3 actives thread instead of the 8 I can have.

我的印象是,如果我每次启动一个线程时都设置AttachedToParent属性,那么B将不会在E、F、G完成之前结束,所以C将在B完成之前开始,我将只有3个活动线程,而不是8个。

If I don't put the AttachedToParent property, A will be finished very fast and return.

如果我不放入AttachedToParent属性,A将很快完成并返回。

So how could I do to ensure that I've always my 8 cores fully used if I don't set this option?

那么,如果我不设置这个选项,我如何确保我的8核始终被充分使用呢?

3 个解决方案

#1


2  

The TaskCreationOptions.AttachedToParent does not prevent the other subtasks from starting, but rather prevents the parent task itself from closing. So when E,F and G are started with AttachedToParent, B is not flagged as finished until all three are finished. So it should do just as you want.

TaskCreationOptions。AttachedToParent并不阻止其他子任务启动,而是阻止父任务本身关闭。因此,当E、F和G与AttachedToParent一起启动时,B不会被标记为finished,直到这三个都完成。所以它应该像你想的那样。

The source (in the accepted answer).

来源(在已接受的答案中)。

#2


2  

As Me.Name mentioned, AttachedToParent doesn't behave according to your impressions. I think it's a fine option in this case.

像我这样的人。提到的名字,AttachedToParent并不是按照您的印象来做的。我认为这是一个很好的选择。

But if you don't want to use that for whatever reason, you can wait for all the child tasks to finish with Task.WaitAll(). Although it means you have to have all of them in a collection.

但是如果您不想出于任何原因使用它,您可以等待所有子任务完成Task.WaitAll()。尽管这意味着你必须将所有这些都放在一个集合中。

Task.WaitAll() blocks the current thread until all the Tasks are finished. If you don't want that and you are on .Net 4.5, you can use Task.WhenAll(), which will return a single Task that will finish when all of the given Tasks finish.

waitall()阻塞当前线程,直到完成所有任务。如果你不想这样,你在。net 4.5中,你可以使用Task. when all(),它将返回一个任务,当所有任务完成时,它将完成。

#3


1  

You could you TaskFactory create options like in this example:

您可以在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();

#1


2  

The TaskCreationOptions.AttachedToParent does not prevent the other subtasks from starting, but rather prevents the parent task itself from closing. So when E,F and G are started with AttachedToParent, B is not flagged as finished until all three are finished. So it should do just as you want.

TaskCreationOptions。AttachedToParent并不阻止其他子任务启动,而是阻止父任务本身关闭。因此,当E、F和G与AttachedToParent一起启动时,B不会被标记为finished,直到这三个都完成。所以它应该像你想的那样。

The source (in the accepted answer).

来源(在已接受的答案中)。

#2


2  

As Me.Name mentioned, AttachedToParent doesn't behave according to your impressions. I think it's a fine option in this case.

像我这样的人。提到的名字,AttachedToParent并不是按照您的印象来做的。我认为这是一个很好的选择。

But if you don't want to use that for whatever reason, you can wait for all the child tasks to finish with Task.WaitAll(). Although it means you have to have all of them in a collection.

但是如果您不想出于任何原因使用它,您可以等待所有子任务完成Task.WaitAll()。尽管这意味着你必须将所有这些都放在一个集合中。

Task.WaitAll() blocks the current thread until all the Tasks are finished. If you don't want that and you are on .Net 4.5, you can use Task.WhenAll(), which will return a single Task that will finish when all of the given Tasks finish.

waitall()阻塞当前线程,直到完成所有任务。如果你不想这样,你在。net 4.5中,你可以使用Task. when all(),它将返回一个任务,当所有任务完成时,它将完成。

#3


1  

You could you TaskFactory create options like in this example:

您可以在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();