Search code examples
c#.netmultithreadingbackgroundworker

.Net: Background Worker and multiple CPU


I am using the BackgroundWorker to do some heavy stuff in the background so that the UI does not become unresponsive.

But today I noticed that when I run my program, only one of the two CPUs is being used.

Is there any way to use all CPUs with the BackgroundWorker?

enter image description here

Here is my simplified code, just if you are curious!


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

Thanks a lot for looking into this :)


Solution

  • The BackgroundWorker does its work within a single background (ThreadPool) thread. As such, if it's computationally heavy, it'll use one CPU heavily. The UI thread is still running on the second, but is probably (like most user interface work) spending almost all of its time idle waiting for input (which is a good thing).

    If you want to split your work up to use more than one CPU, you'll need to use some other techniques. This could be multiple BackgroundWorker components, each doing some work, or using the ThreadPool directly. Parallel programming has been simplified in .NET 4 via the TPL, which is likely a very good option. For details, you can see my series on the TPL or MSDN's page on the Task Parallel Library.