Alex
Alex

Reputation: 6149

Change normal loop to Parallel loop

I have the following code:

static void Main(string[] args)
{
   TaskExecuter.Execute();
}

class Task
{
        int _delay;
        private Task(int delay) { _delay = delay; }
        public void Execute() { Thread.Sleep(_delay); }
        public static IEnumerable GetAllTasks()
        {
            Random r = new Random(4711);
            for (int i = 0; i < 10; i++)
                yield return new Task(r.Next(100, 5000));
        }
 }

static class TaskExecuter
{
        public static void Execute()
        {
            foreach (Task task in Task.GetAllTasks())
            {
                 task.Execute();
            }
        }
   }

I need to change the loop in Execute method to paralle with multiple threads, I tried the following, but it isn't working since GetAllTasks returns IEnumerable and not a list

Parallel.ForEach(Task.GetAllTasks(), task =>
{
   //Execute();
});

Upvotes: 0

Views: 323

Answers (3)

Douglas
Douglas

Reputation: 54887

Parallel.ForEach takes an IEnumerable<TSource>, so your code should be fine. However, you need to perform the Execute call on the task instance that is passed as parameter to your lambda statement.

Parallel.ForEach(Task.GetAllTasks(), task =>
{
    task.Execute();
});

This can also be expressed as a one-line lambda expression:

Parallel.ForEach(Task.GetAllTasks(), task => task.Execute());

There is also another subtle bug in your code that you should pay attention to. Per its internal implementation, Parallel.ForEach may enumerate the elements of your sequence in parallel. However, you are calling an instance method of the Random class in your enumerator, which is not thread-safe, possibly leading to race issues. The easiest way to work around this would be to pre-populate your sequence as a list:

Parallel.ForEach(Task.GetAllTasks().ToList(), task => task.Execute());

Upvotes: 2

NeddySpaghetti
NeddySpaghetti

Reputation: 13495

This worked on my linqpad. I just renamed your Task class to Work and also returned an IEnumerable<T> from GetAllTasks:

class Work
{
        int _delay;
        private Work(int delay) { _delay = delay; }
        public void Execute() { Thread.Sleep(_delay); }
        public static IEnumerable<Work> GetAllTasks()
        {
            Random r = new Random(4711);
            for (int i = 0; i < 10; i++)
                yield return new Work(r.Next(100, 5000));
        }
 }

static class TaskExecuter
{
        public static void Execute()
        {
            foreach (Work task in Work.GetAllTasks())
            {
                 task.Execute();
            }
        }
   }
void Main()
{
    System.Threading.Tasks.Parallel.ForEach(Work.GetAllTasks(), new Action<Work>(task =>
{
   //Execute();
}));
}

Upvotes: 0

Giedrius
Giedrius

Reputation: 8540

Parallel.ForEach works with IEnumerable<T>, so adjust your GetAllTasks to return IEnumerable<Task>.

Also .net has widely used Task class, I would avoid naming own class like that to avoid confusion.

Upvotes: 3

Related Questions