问题
I need to start a "number" of tasks (variable but less than 10) not in parallel, and wait for them all to finish, getting from each the result. I'm getting the result from each of them, saving in a list and then using it in the end.
Here's my code, and it's working but I think there gotta be a cleaner way to do that.
CAUSING THE NUMBER OF TASKS
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);
}
回答1:
You do not need the Wait()
call. Documentation for Task<T>.Result states:
Accessing the property's get accessor blocks the calling thread until the asynchronous operation is complete; it is equivalent to calling the Wait method.
回答2:
I think this is what you are attempting to do : ie start a whole load of parallel tasks and wait for them all to complete before proceeding
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;
}
}
回答3:
you can use async await
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;
}
回答4:
Your entire code, as of now, runs synchronously. You're creating a Task
then actively blocking on it, using Task.Result
.
If you truly understand what parallelism is about, and you really need to execute as many tasks as you have arguments in your list, then you can offload all of them and then asynchronously wait (this is the key, being asynchronous) as they complete:
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);
}
Edit: From your comments:
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
Then you don't need a thread for each argument at all. Two things:
- You can make the call entirely synchronous, as you have to wait for the completion of each call. Using threadpool threads for that is merely useless
- You can make asynchronous calls without needing to use threads at all. Look into
HttpClient
and itsXXXAsync
methods (such asGetAsync
).
来源:https://stackoverflow.com/questions/29693791/run-multiple-tasks-variable-number-in-parallel-and-continue-when-all-have-fini