Reputation: 575
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);
}
Upvotes: 5
Views: 3123
Reputation: 149656
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:
HttpClient
and its XXXAsync
methods (such as GetAsync
).Upvotes: 0
Reputation: 1320
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;
}
}
Upvotes: 5
Reputation: 1097
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;
}
Upvotes: 0
Reputation: 31203
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.
Upvotes: 1