【问题标题】:foreach to Parallel.ForEachforeach 到 Parallel.ForEach
【发布时间】:2015-03-27 13:55:50
【问题描述】:

我有一个正在运行的任务,但我对它的速度不满意,所以我决定把它变成 Parallel.ForEach,因为它更快,谁能帮我把这个函数变成 Parallel.ForEach,谢谢。

        private async void run_task()
        {
            cancellationTokenSource = new CancellationTokenSource();
            cancellationToken = cancellationTokenSource.Token;
            label20.Text = "";
            foreach (var node2 in checkedListBox1.CheckedItems)
            {
                progressBar1.Value = 0;
                rd node = (rd)node2;
                node.max_chp = await mc(node.link);
                for (int ii = 1; ii <= node.max_chp; ii++)
                {
                    progressBar1.Value = (int)(((decimal)ii / (decimal)node.max_chp) * 100);
                    byte[] data = null;
                    string add;
                    using (WebClient client = new WebClient())
                    {
                        client.Proxy = null;
                        if (ii == 1)
                        {
                            add = node.link;
                        }
                        else
                        {
                            add = node.link + ii.ToString() + ".html";
                        }
                        string tem = await get_pics(add, ii - 1);
                        label20.Text = add;
                        using (Task<byte[]> task = Task.Factory.StartNew<byte[]>(() => dl_data(client, tem), cancellationToken))
                        {
                            try
                            {
                                await task;
                            }
                            catch
                            {
                                dis_GUI(true, 1);
                                label20.Text = "";
                                progressBar1.Value = 0;
                                pictureBox3.Visible = false;
                                return;
                            }
                            data = task.Result;                                        
                        }
                    }
                    string subPath = node.name;
                    subPath = System.Text.RegularExpressions.Regex.Replace(subPath, "[^0-9a-zA-Z.]+", " ");
                    subPath = System.Text.RegularExpressions.Regex.Replace(subPath, @"\d+", n => n.Value.PadLeft(3, '0'));
                    string path = Path.Combine(files, subPath);
                    System.IO.Directory.CreateDirectory(path);
                    File.WriteAllBytes(Path.Combine(path, ii.ToString().PadLeft(3, '0') + ".jpg"), data);
                }
            }
            dis_GUI(true, 1);
            label20.Text = "";
            progressBar1.Value = 0;
            pictureBox3.Visible = false;
        }

我知道我的代码做得不好,但请放心。

【问题讨论】:

  • 我强烈建议您将小部分逻辑提取到单独的方法中。
  • 如果不尝试,您将不会获得太多帮助。你的问题是“我想要这个,我想要你为我做这件事”

标签: c# foreach parallel.foreach


【解决方案1】:

您的 foreach 语句中似乎有更新 UI 的代码,您希望将其转换为并行。 不建议这样做: 如果确实在 UI 线程上运行并行循环,请注意避免从循环内更新 UI 控件。尝试从在 UI 线程上执行的并行循环内更新 UI 控件可能会导致状态损坏、异常、延迟更新甚至死锁,具体取决于调用 UI 更新的方式。在下面的示例中,并行循环会阻塞正在执行它的 UI 线程,直到所有迭代都完成。但是,如果循环的迭代正在后台线程上运行(如 For 可能所做的那样),则对 Invoke 的调用会导致将消息提交给 UI 线程并阻塞等待该消息被处理。由于运行 For 的 UI 线程被阻塞,消息永远无法处理,UI 线程死锁。 来源:https://msdn.microsoft.com/en-us/library/dd997392(v=vs.110).aspx

【讨论】:

    【解决方案2】:

    由于您承认自己需要帮助并且您是编程新手,因此我将与您分享一些最佳实践,而不是为您编写代码。

    因此,首先,您几乎不应该在并行循环中进行任何类型的 UI 操作。当您使用Parallel.ForEach 时,您正在迭代的集合中的项目不会按顺序处理。请注意,您在循环中引用了progressBar1。这对于连续的for 循环来说很好,但是当并行完成时,多个线程会尝试同时更新同一个对象,并且没有可预测的顺序。你会遇到所谓的“竞争条件”,它会做各种奇怪的事情,甚至可能让它变慢。在执行非平凡的并行操作时,创建和管理线程会产生开销。对于小型收藏,您不太可能获得您想要的收益。

    在这种特殊情况下,您应该考虑如何以更有效的方式编写您正在做的事情。这将使您成为更好的程序员。新开发人员经常会立即考虑将一些缓慢的迭代并行化以使其更快,但这很可能不是正确的做法,并发性也不是一件容易管理的事情。

    【讨论】:

      猜你喜欢
      • 2011-08-27
      • 2011-04-16
      • 1970-01-01
      • 1970-01-01
      • 2020-04-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多