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:
通过这个过程树
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 Task
s 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 Task
s 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 Task
s 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 Task
s 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();