【问题标题】:Change normal loop to Parallel loop将正常循环更改为并行循环
【发布时间】:2013-06-06 11:22:25
【问题描述】:

我有以下代码:

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 方法中的循环更改为与多个线程并行,我尝试了以下方法,但它不起作用,因为 GetAllTask​​s 返回 IEnumerable 而不是列表

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

【问题讨论】:

  • 也许这会有所帮助:stackoverflow.com/questions/7617771/…
  • @Giedrius 谢谢,如果这是我会给你 25 分的答案,那就对了
  • 你可能不应该给你的班级打电话Task,以免与System.Threading.Tasks.Task混淆。

标签: c# .net parallel.foreach


【解决方案1】:

Parallel.ForEachIEnumerable&lt;T&gt; 一起使用,因此调整您的GetAllTasks 以返回IEnumerable&lt;Task&gt;

.net 也广泛使用 Task 类,我会避免这样命名自己的类以避免混淆。

【讨论】:

    【解决方案2】:

    Parallel.ForEach 采用IEnumerable&lt;TSource&gt;,所以你的代码应该没问题。但是,您需要对作为参数传递给 lambda 语句的 task 实例执行 Execute 调用。

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

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

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

    您的代码中还有另一个需要注意的细微错误。根据其内部实现,Parallel.ForEach 可能是enumerate the elements of your sequence in parallel。但是,您正在枚举器中调用 Random 类的实例方法,这不是线程安全的,可能会导致竞争问题。解决此问题的最简单方法是将序列预填充为列表:

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

    【讨论】:

    • Parallel.ForEach() 可以从多个线程中枚举,但不能并行。它使用锁定来确保一次只枚举一个线程。所以Random的用法没问题。
    • @svick:你是对的;我被链接帖子中的第一个回复(由知名贡献者撰写)误导了。感谢您的澄清。
    【解决方案3】:

    这在我的 linqpad 上有效。我刚刚将您的 Task 类重命名为 Work 并且还从 GetAllTasks 返回了 IEnumerable&lt;T&gt;

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-01-03
      • 2018-08-13
      • 2017-09-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多