Запустите несколько задач (номер переменной) параллельно и продолжите, когда все они будут завершены

Мне нужно не "параллельно" запускать "количество" задач (переменное, но меньше 10) и ждать, пока все они завершатся, получая по каждому результату. Я получаю результаты от каждого из них, сохраняю их в списке и затем использую в конце.

Вот мой код, и он работает, но я думаю, что должен быть более чистый способ сделать это.

ПРИЧИНЯЯ ЧИСЛО ЗАДАЧ

List<String> Arguments = new List<String> { "AA", "BB", "CC" }; 

List<String> ResultList = new List<String>();  

//**AT LEAST I'VE GOT ONE**

Task<String> Tasks = Task<String>.Factory.StartNew(() =>
{
    return DoSomething(Arguments[0]);
});

ResultList.Add(Tasks.Result);

for (Int32 i = 1; i < Arguments.Count; i++)
{
    ResultList.Add(Tasks.ContinueWith<String>(Result =>
    {
        return DoSomething(Arguments[i]);

    }).Result);
}

//**DO I NEED THIS?? It's working even without!!**
//Tasks.Wait();

for (Int32 i = 0; i < ResultList.Count; i++)
{
    textBox1.AppendText(ResultList[i] + Environment.NewLine + Environment.NewLine);
}

4 ответа

Решение

Вам не нужно Wait() вызов. Документация к заданию. Результат гласит:

Доступ к свойству get метода доступа блокирует вызывающий поток до тех пор, пока асинхронная операция не будет завершена; это эквивалентно вызову метода Wait.

Я думаю, что это то, что вы пытаетесь сделать: т.е. запустить целую загрузку параллельных задач и подождать, пока все они завершатся, прежде чем продолжить

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace UnitTestProject2
{
    class Class4
    {
        public void run()
        {
            List<String> Arguments = new List<String> { "AA", "BB", "CC" };
            List<Task<String>> tasks = new List<Task<string>>();

            foreach (string arg in Arguments)
            {
                    tasks.Add(
                        this.DoSomething(arg)
                        .ContinueWith(t => this.DoSomething(t.Result))
                        .Unwrap<string>()
                    );
            }

            Task.WaitAll(tasks.ToArray());

            foreach(Task<string> t in tasks)
            {
                textBox1 += (t.Result + Environment.NewLine + Environment.NewLine);
            }

        }

        public async Task<string> DoSomething(string arg)
        {
            return arg;
        }

        public string textBox1;
    }
}

Вы можете использовать асинхронное ожидание

public async List<String> SomeMethod() {
   List<String> Arguments = new List<String> { "AA", "BB", "CC" }; 
   List<String> ResultList = new List<String>();  
   foreach(var argument in Arguments) 
   {
     var result = await DoSomething(argument);
     ResultList.Add(result);
   }
   return ResultList;
}

Весь ваш код на данный момент работает синхронно. Вы создаете Task затем активно блокирую на нем, используя Task.Result,

Если вы действительно понимаете, что такое параллелизм, и вам действительно нужно выполнить столько задач, сколько у вас есть аргументов в вашем списке, то вы можете разгрузить все из них и затем асинхронно ждать (это ключ, будучи асинхронным) по мере их завершения:

var arguments = new[] { "A", "B", "C" };
var tasks = arguments.Select(argument => Task.Run(() => DoSomething(argument))).ToList();

while (tasks.Count > 0)
{
    var finishedTask = await Task.WhenAny(tasks);
    textBox1.AppendText(string.Format("{0}{1}{1}", finishedTask.Result,
                                                   Environment.NewLine));

    tasks.Remove(finishedTask);
}

Изменить: Из ваших комментариев:

Я вызываю веб-интерфейс (не мой), который не позволяет мне выполнять несколько вызовов параллельно, поэтому мне нужно дождаться завершения каждой задачи

Тогда вам не нужен поток для каждого аргумента вообще. Две вещи:

  1. Вы можете сделать вызов полностью синхронным, так как вам придется ждать завершения каждого вызова. Использование потоков пула для этого просто бесполезно
  2. Вы можете делать асинхронные вызовы без необходимости использовать потоки вообще. Заглянуть в HttpClient И его XXXAsync методы (такие как GetAsync).
Другие вопросы по тегам