frenchie
frenchie

Reputation: 52017

Creating a task inside a foreach loop

I have a typical foreach loop that calls a method where the parameter is an element of the collection we're looping over; something like this:

foreach (byte x in SomeCollection)
{
   SomeMethod(x);
}

The problem is that SomeMethod takes a long time to run. I want to move the call into a new task so that the loop just creates the tasks and then the thread that called the loops just continues. How do I do this in a thread-safe way?

Edit

I had a performance issue because SomeMethod makes several DB calls. So I converted the loop to a Parallel.ForEach but that didn't make much of a difference because each thread then call the DB. What I'm looking to do is just create Tasks that will run in the background and let the main thread continue.

Upvotes: 8

Views: 14273

Answers (3)

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726929

One way would be to use Parallel.ForEach to do this:

Parallel.ForEach(SomeCollection, x => SomeMethod(x));

The code would wait for all calls of SomeMethod to complete before proceeding, but the individual calls may run in parallel.

If you don't want to wait for the calls to finish, wrap this call in StartNew:

Task.Factory.StartNew(() => Parallel.ForEach(SomeCollection, x => SomeMethod(x)));

Upvotes: 15

poy
poy

Reputation: 10527

You could something like:

IEnumerable<Task> doWork()
{
  foreach(var x in SomeCollection)
    yield return Task.Run(()=>SomeMethod(x);
}

Task.WhenAll(doWork());

This will run them all at the same time.

Upvotes: 1

Dennis
Dennis

Reputation: 37780

What thread safety do you expect? This will be thread-safe:

foreach (byte x in SomeCollection) { Task.Factory.StartNew(() => SomeMethod(x)); }

until your method does not modify any shared state, which isn't thread-safe itself.

Upvotes: 1

Related Questions