运行 多个任务(可变数量)并行并在所有任务完成后继续
Run Multiple Tasks (Variable Number) in parallel and continue when all have finished
我需要启动 "number" 个非并行任务(可变但少于 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);
}
您不需要 Wait()
调用。 Task<T>.Result 的文档说明:
Accessing the property's get accessor blocks the calling thread until the asynchronous operation is complete; it is equivalent to calling the Wait method.
你可以使用异步等待
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;
}
我认为这就是您正在尝试做的事情:即启动一整套并行任务并等待它们全部完成后再继续
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;
}
}
到目前为止,您的整个代码都是同步运行的。您正在创建一个 Task
然后主动阻止它,使用 Task.Result
.
如果您真正理解什么是并行性,并且您确实需要执行与列表中的参数一样多的任务,那么您可以卸载所有任务然后异步等待(这是 key,当它们完成时 异步):
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);
}
编辑:
来自您的评论:
I'm calling a web api (Not mine) that doesn't allow me multiple call
in parallel, that's why I need to wait for each task to finish
那么您根本不需要为每个参数创建线程。两件事:
- 您可以使调用完全同步,因为您必须等待每个调用完成。为此使用线程池线程毫无用处
- 您可以在根本不需要使用线程的情况下进行异步调用。查看
HttpClient
及其 XXXAsync
方法(例如 GetAsync
)。
我需要启动 "number" 个非并行任务(可变但少于 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);
}
您不需要 Wait()
调用。 Task<T>.Result 的文档说明:
Accessing the property's get accessor blocks the calling thread until the asynchronous operation is complete; it is equivalent to calling the Wait method.
你可以使用异步等待
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;
}
我认为这就是您正在尝试做的事情:即启动一整套并行任务并等待它们全部完成后再继续
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;
}
}
到目前为止,您的整个代码都是同步运行的。您正在创建一个 Task
然后主动阻止它,使用 Task.Result
.
如果您真正理解什么是并行性,并且您确实需要执行与列表中的参数一样多的任务,那么您可以卸载所有任务然后异步等待(这是 key,当它们完成时 异步):
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);
}
编辑: 来自您的评论:
I'm calling a web api (Not mine) that doesn't allow me multiple call in parallel, that's why I need to wait for each task to finish
那么您根本不需要为每个参数创建线程。两件事:
- 您可以使调用完全同步,因为您必须等待每个调用完成。为此使用线程池线程毫无用处
- 您可以在根本不需要使用线程的情况下进行异步调用。查看
HttpClient
及其XXXAsync
方法(例如GetAsync
)。