Запустите несколько задач (номер переменной) параллельно и продолжите, когда все они будут завершены
Мне нужно не "параллельно" запускать "количество" задач (переменное, но меньше 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);
}
Изменить: Из ваших комментариев:
Я вызываю веб-интерфейс (не мой), который не позволяет мне выполнять несколько вызовов параллельно, поэтому мне нужно дождаться завершения каждой задачи
Тогда вам не нужен поток для каждого аргумента вообще. Две вещи:
- Вы можете сделать вызов полностью синхронным, так как вам придется ждать завершения каждого вызова. Использование потоков пула для этого просто бесполезно
- Вы можете делать асинхронные вызовы без необходимости использовать потоки вообще. Заглянуть в
HttpClient
И егоXXXAsync
методы (такие какGetAsync
).