首页 文章

将正常循环更改为并行循环

提问于
浏览
0

我有以下代码:

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();
            }
        }
   }

我需要将Execute方法中的循环更改为与多个线程并行,我尝试了以下操作,但由于GetAllTasks返回IEnumerable而不是列表,因此无法正常工作

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

3 回答

  • 2

    Parallel.ForEach 适用于 IEnumerable<T> ,因此请调整 GetAllTasks 以返回 IEnumerable<Task> .

    另外.net已广泛使用Task类,我会避免命名自己的类来避免混淆 .

  • 3

    这适用于我的linqpad . 我刚刚将 Task 类重命名为 Work ,并从 GetAllTasks 返回了 IEnumerable<T>

    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();
    }));
    }
    
  • 0

    Parallel.ForEach需要 IEnumerable<TSource> ,因此您的代码应该没问题 . 但是,您需要在作为参数传递给lambda语句的 task 实例上执行 Execute 调用 .

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

    这也可以表示为单行lambda表达式:

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

    您的代码中还有另一个微妙的错误,您应该注意 . 根据其内部实现,Parallel.ForEach可以并行枚举序列的元素 . 但是,您在枚举器中调用Random类的实例方法,该方法不是线程安全的,可能导致种族问题 . 解决此问题的最简单方法是将序列预先填充为列表:
    Parallel.ForEach(Task.GetAllTasks() . ToList(),task => task.Execute());

相关问题