【问题标题】:.Net: Background Worker and multiple CPU.Net:后台工作者和多 CPU
【发布时间】:2011-12-07 22:57:45
【问题描述】:

我正在使用BackgroundWorker 在后台做一些繁重的工作,这样 UI 就不会变得无响应。

但今天我注意到,当我运行我的程序时,两个 CPU 中只使用了一个。

有没有办法使用BackgroundWorker所有 CPU?

这是我的简化代码,如果你好奇的话!


private System.ComponentModel.BackgroundWorker bwPatchApplier;

this.bwPatchApplier.WorkerReportsProgress = true;
this.bwPatchApplier.DoWork += new System.ComponentModel.DoWorkEventHandler(this.bwPatchApplier_DoWork);
this.bwPatchApplier.ProgressChanged += new System.ComponentModel.ProgressChangedEventHandler(this.bwPatchApplier_ProgressChanged);
this.bwPatchApplier.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.bwPatchApplier_RunWorkerCompleted);

private void bwPatchApplier_DoWork(object sender, DoWorkEventArgs e)
{
    string pc1WorkflowName;
    string pc2WorkflowName;

    if (!GetWorkflowSettings(out pc1WorkflowName, out pc2WorkflowName)) return;

    int progressPercentage = 0;
    var weWorkspaces = (List<WEWorkspace>) e.Argument;

    foreach (WEWorkspace weWorkspace in weWorkspaces)
    {
        using (var spSite = new SPSite(weWorkspace.SiteId))
        {
            foreach (SPWeb web in spSite.AllWebs)
            {
                using (SPWeb spWeb = spSite.OpenWeb(web.ID))
                {
                    PrintHeader(spWeb.ID, spWeb.Title, spWeb.Url, bwPatchApplier);

                    try
                    {
                        for (int index = 0; index < spWeb.Lists.Count; index++)
                        {
                            SPList spList = spWeb.Lists[index];

                            if (spList.Hidden) continue;

                            string listName = spList.Title;

                            if (listName.Equals("PC1") || listName.Equals("PC2"))
                            {
                                #region STEP 1

                                // STEP 1: Remove Workflow

                                #endregion

                                #region STEP 2

                                // STEP 2: Add Events: Adding & Updating

                                #endregion
                            }

                            if ((uint) spList.BaseTemplate == 10135 || (uint) spList.BaseTemplate == 10134)
                            {
                                #region STEP 3

                                // STEP 3: Configure Custom AssignedToEmail Property

                                #endregion

                                #region STEP 4

                                if (enableAssignToEmail)
                                {
                                    // STEP 4: Install AssignedTo events to Work lists
                                }

                                #endregion
                            }

                            #region STEP 5

                            // STEP 5 Install Notification Events

                            #endregion

                            #region STEP 6

                            // STEP 6 Install Report List Events

                            #endregion

                            progressPercentage += TotalSteps;
                            UpdatePercentage(progressPercentage, bwPatchApplier);
                        }
                    }
                    catch (Exception exception)
                    {
                        progressPercentage += TotalSteps;
                        UpdatePercentage(progressPercentage, bwPatchApplier);
                    }
                }
            }
        }
    }

    PrintMessage(string.Empty, bwPatchApplier);
    PrintMessage("*** Process Completed", bwPatchApplier);

    UpdateStatus("Process Completed", bwPatchApplier);
}

非常感谢您对此进行调查 :)

【问题讨论】:

    标签: c# .net multithreading backgroundworker


    【解决方案1】:

    BackgroundWorker 在单个后台 (ThreadPool) 线程中工作。因此,如果它的计算量很大,它将大量使用一个 CPU。 UI 线程仍然在第二个运行,但可能(像大多数用户界面工作一样)几乎所有时间都在空闲等待输入(这是一件好事)。

    如果您想将工作拆分为使用多个 CPU,则需要使用其他一些技术。这可能是多个BackgroundWorker 组件,每个组件都在做一些工作,或者直接使用线程池。 .NET 4 通过 TPL 简化了并行编程,这可能是一个非常好的选择。详情可以看my series on the TPLMSDN's page on the Task Parallel Library

    【讨论】:

      【解决方案2】:

      每个 BackgroundWorker 只使用一个线程来执行您告诉它执行的操作。要利用多个内核,您需要多个线程。这将意味着多个 BackgroundWorkers 或从您的 DoWork 方法中产生多个线程。

      【讨论】:

        【解决方案3】:

        backgroundworker 本身只提供一个额外的执行线程。它的目的是让事情脱离 UI 线程,而且它非常擅长这项工作。如果你想要更多的线程,你需要自己提供。

        这里很容易构建一个接受 SPWeb 参数的方法,并为每个对象一遍又一遍地调用 Thread.Start();然后使用 Thread.Join() 或 WaitAll() 完成以等待它们在 BackgroundWorker 结束时完成。但是,这将是一个坏主意,因为您将失去效率,因为操作系统会花时间在所有线程之间执行上下文切换。

        相反,您希望强制您的系统仅在几个线程中运行,但至少在两个线程中运行(在这种情况下)。一个好的经验法则是 (2n - 1),其中“n”是您拥有的处理器内核数……但在各种情况下您都想打破这个规则。您可以通过使用 ThreadPool、遍历您的 SPWeb 对象并将它们添加到您不断从中提取的队列或其他方式(例如 TPL)来实现此目的。

        【讨论】:

          【解决方案4】:

          BackgroundWorker 在第二个 CPU 内核上运行一个新线程,让 UI 响应。

          如果您使用的是 .NET 4,请考虑使用 Task Parallel Library,它可以为您提供更好的结果并利用两个内核。

          【讨论】:

            【解决方案5】:

            BackgroundWorker 本身只是在您的主 UI 之外创建一个单独的线程来执行工作 - 它不会尝试并行化该工作线程中的操作。如果您想将您的工作分散到多个工作线程中,您应该考虑使用TPL。请记住,并非所有任务都能很好地转换为并行执行,因此如果释放 UI 是您的唯一目标,这可能已经是您能做的最好的事情了。

            【讨论】:

              【解决方案6】:

              这有潜在的陷阱,但您可能会从使用 Parallel.ForEach 中获得一些好处:

              代替

              foreach (SPWeb web in spSite.AllWebs)
              {
                  //Your loop code here
              }        
              

              你可以:

              Parallel.Foreach(spSite.AllWebs, web =>
                      {
                        //Your loop code here
                      });
              

              这基本上从每个项目创建一个任务(来自 .NET 4.0 中的任务 API),并安排与任务池一起使用,这将为您提供利用这些内核所需的一些并行性。

              您将不得不解决可能由此产生的不可避免的并发问题,但这是一个很好的起点。您将至少解决您在线程之间维护共享状态(进度计数器)的事实。这里有一些指导:http://msdn.microsoft.com/en-us/library/dd997392.aspx

              【讨论】:

                猜你喜欢
                • 2015-10-12
                • 1970-01-01
                • 1970-01-01
                • 2023-03-27
                • 1970-01-01
                • 2011-07-18
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多