В продолжение вот этого вопроса.
Итак, пусть есть несколько асинхронных методов
async Task DoFoo() { ... }
async Task DoBar() { ... }
async Task DoBaz() { ... }
которые в другом асинхронном методе
async Task DoJob()
{
//TODO: perform DoFoo, DoBar and DoBaz in parallel
}
требуется выполнить параллельно.
Если следовать ответам в упомянутом вопросе, то для параллельности выполнения нескольких асинхронных методов нужно вызвать их так:
async Task DoJob()
{
Task t1 = DoFoo();
Task t2 = DoBar();
Task t3 = DoBaz();
await Task.WhenAll(t1, t2, t3);
}
В документации по TaskScheduler, однако, читаю:
Top-level tasks, which are tasks that are not created in the context of another task, are put on the global queue just like any other work item. However, nested or child tasks, which are created in the context of another task, are handled quite differently. A child or nested task is put on a local queue that is specific to the thread on which the parent task is executing. The parent task may be a top-level task or it also may be the child of another task. When this thread is ready for more work, it first looks in the local queue.
Применительно к ситуации, если я правильно понимаю, задачи t1, t2, t3 не являются задачами корневого уровня (т.к. они вложены в DoJob), и потому, стартуя они попадают не в global queue, которая обрабатывается множеством потоков пула, а - в local queue какого-то одного конкретного потока.
Получается, что многопоточного исполнения нескольких асинхронных методов такой способ не даёт?
Да, может произойти work stealing, но стоит ли на него надеяться, или для достижения параллелизма лучше все методы обернуть в Task.Run(...) (который отправит задачи исполняться на пуле потоков, т.е., по-видимому, в global queue)
async Task DoJob()
{
Task t1 = Task.Run(DoFoo);
Task t2 = Task.Run(DoBar);
Task t3 = Task.Run(DoBaz);
await Task.WhenAll(t1, t2, t3);
}
?
nested or child tasks- это совсем другой механизм, не связанный с приведенным автором кодом. – Pavel Mayorov Feb 12 '18 at 16:17Task t1 = DoFoo();разве не порождает detached child task? – i-one Feb 12 '18 at 16:30!=. Единственное, что кажется я уравнял - это многопоточность и параллельность, но таково положение вещей и в исходном вопросе. – i-one Feb 12 '18 at 16:32Task.CurrentId– Pavel Mayorov Feb 13 '18 at 06:33Task t1 = DoFoo();, это как-то представимо черезTask.Factory.StartNew(...)илиvar t = new Task(...); t.Start();? – i-one Feb 13 '18 at 06:39TaskScheduler.Defaultили как-то иначе? Из описания класса TaskScheduler сложилось именно такое впечателние. И даже еслиTask t1 = DoFoo();нельзя назвать child, очень похоже, однако, что процитированное имеет место быть, t1, t2, t3 попадают по-видимому именно в local queue, т.е. имеет место быть однопоточное последовательное либо квазипараллельное (одним потоком) исполнение методов. – i-one Feb 13 '18 at 07:01TaskScheduler.Default, забудьте про него. "t1, t2, t3 попадают по-видимому именно в local queue" - нет, не попадают. – Pavel Mayorov Feb 13 '18 at 07:20