【问题标题】:How to use multiple background workers in a loop in which to start new work each iteration for each background worker in C#如何在循环中使用多个后台工作人员,在 C# 中为每个后台工作人员每次迭代开始新工作
【发布时间】:2017-09-13 21:30:25
【问题描述】:

我需要使用 4 个后台工作人员在特定坐标上并行移动 4 个对象,即一起启动它们并一起停止它们。

我写了一个循环来循环 50 次,每次我需要启动工作人员并在他们完成工作后,如 Do_Work() 方法中那样停止它并在下一次迭代中再次启动它们,我编写了以下方法来调用工人:

public void Genetic_Algorithm(List<int[,]> population)
        {


            DateTime startT = DateTime.Now.Date;

            double[,] FitnessValue = new double[6, 2]; // for all five chromosome we store two Values the Fitness Value and the Fitness Ratio

            int[] RouletteWheel = new int[6];

            int round = 0;



            for (geneticIteration = 0; geneticIteration < 50; geneticIteration++)
            {



                round = geneticIteration + 1;


                // Calculate the fitness Function and the Fitness Ratio

                FitnessFunction(population); // Fitness Function


            }



            MessageBox.Show("Press Again");


        } 




 public void FitnessFunction(List<int[,]> population)
        {

            extractPath(population, geneticIteration);

            auv0Genetic.RunWorkerAsync(); // start obj # 1
            auv1Genetic.RunWorkerAsync(); // start obj # 2
            auv2Genetic.RunWorkerAsync(); // start obj # 3
            auv3Genetic.RunWorkerAsync(); // start obj # 4


        }

它们是 4 个方法 Do_Work() 用于 4 个后台工作人员,以下是其中之一:

private void auv0Genetic_DoWork(object sender, DoWorkEventArgs e)
        {

            List<PointF> genetic2DLayerPath1 = new List<PointF>(); //  from chromosome 1

            List<PointF> genetic2DLayerPath2 = new List<PointF>(); //  from chromosome 2

            List<PointF> genetic2DLayerPath3 = new List<PointF>(); //  from chromosome 3

            List<PointF> genetic2DLayerPath4 = new List<PointF>(); //  from chromosome 4

            List<PointF> genetic2DLayerPath5 = new List<PointF>(); //  from chromosome 5

            List<PointF> genetic2DLayerPath6 = new List<PointF>(); //  from chromosome 6

            countNumOfPaths = 0;

            float[] xPoints = new float[1];

            float[] yPoints = new float[1]; 


            foreach (int[,] arr in pathChromosom1)
            {

                Point3D pointIn3D = new Point3D(cellsCenters[0, arr[0, 0]], cellsCenters[1, arr[1, 0]], 700);

                PointF pointIn2D = Project(pointIn3D); // convert to 2D

                genetic2DLayerPath1.Add(pointIn2D);

            }


            foreach (int[,] arr in pathChromosom2)
            {

                Point3D pointIn3D = new Point3D(cellsCenters[0, arr[0, 0]], cellsCenters[1, arr[1, 0]], 700);

                PointF pointIn2D = Project(pointIn3D); // convert to 2D

                genetic2DLayerPath2.Add(pointIn2D);

            }


            foreach (int[,] arr in pathChromosom3)
            {

                Point3D pointIn3D = new Point3D(cellsCenters[0, arr[0, 0]], cellsCenters[1, arr[1, 0]], 700);

                PointF pointIn2D = Project(pointIn3D); // convert to 2D

                genetic2DLayerPath3.Add(pointIn2D);

            }


            foreach (int[,] arr in pathChromosom4)
            {

                Point3D pointIn3D = new Point3D(cellsCenters[0, arr[0, 0]], cellsCenters[1, arr[1, 0]], 700);

                PointF pointIn2D = Project(pointIn3D); // convert to 2D

                genetic2DLayerPath4.Add(pointIn2D);

            }



            foreach (int[,] arr in pathChromosom5)
            {

                Point3D pointIn3D = new Point3D(cellsCenters[0, arr[0, 0]], cellsCenters[1, arr[1, 0]], 700);

                PointF pointIn2D = Project(pointIn3D); // convert to 2D

                genetic2DLayerPath5.Add(pointIn2D);

            }

            foreach (int[,] arr in pathChromosom6)
            {

                Point3D pointIn3D = new Point3D(cellsCenters[0, arr[0, 0]], cellsCenters[1, arr[1, 0]], 700);

                PointF pointIn2D = Project(pointIn3D); // convert to 2D

                genetic2DLayerPath6.Add(pointIn2D);

            }

            int counter = 0;

            for (int i = 0; i < 6; i++)
            {


                if (i == 0) // first chromosome
                {
                     xPoints = new float[genetic2DLayerPath1.Count()];

                     yPoints = new float[genetic2DLayerPath1.Count()];



                    auv[0].auvDepth = 700;


                    foreach(PointF p in genetic2DLayerPath1)
                    {

                        xPoints[counter] = p.X;

                        yPoints[counter] = p.Y;

                        counter++;

                    }

                    counter = 0;

                }


                if (i == 1) // second chromosome
                {
                     xPoints = new float[genetic2DLayerPath2.Count()];

                     yPoints = new float[genetic2DLayerPath2.Count()];



                    auv[0].auvDepth = 700;


                    foreach (PointF p in genetic2DLayerPath2)
                    {

                        xPoints[counter] = p.X;

                        yPoints[counter] = p.Y;

                        counter++;

                    }

                    counter = 0;

                }


                if (i == 2) // third chromosome
                {
                     xPoints = new float[genetic2DLayerPath3.Count()];

                     yPoints = new float[genetic2DLayerPath3.Count()];



                    auv[0].auvDepth = 700;


                    foreach (PointF p in genetic2DLayerPath3)
                    {

                        xPoints[counter] = p.X;

                        yPoints[counter] = p.Y;

                        counter++;

                    }


                    counter = 0;

                }

                if (i == 3) // fourth chromosome
                {
                     xPoints = new float[genetic2DLayerPath4.Count()];

                     yPoints = new float[genetic2DLayerPath4.Count()];



                    auv[0].auvDepth = 700;


                    foreach (PointF p in genetic2DLayerPath4)
                    {

                        xPoints[counter] = p.X;

                        yPoints[counter] = p.Y;

                        counter++;

                    }

                    counter = 0;

                }

                if (i == 4) // fifth chromosome
                {
                     xPoints = new float[genetic2DLayerPath5.Count()];

                     yPoints = new float[genetic2DLayerPath5.Count()];



                    auv[0].auvDepth = 700;


                    foreach (PointF p in genetic2DLayerPath5)
                    {

                        xPoints[counter] = p.X;

                        yPoints[counter] = p.Y;

                        counter++;

                    }

                    counter = 0;

                }


                if (i == 5) // sixth chromosome
                {
                    xPoints = new float[genetic2DLayerPath6.Count()];

                    yPoints = new float[genetic2DLayerPath6.Count()];



                    auv[0].auvDepth = 700;


                    foreach (PointF p in genetic2DLayerPath6)
                    {

                        xPoints[counter] = p.X;

                        yPoints[counter] = p.Y;

                        counter++;

                    }

                    counter = 0;

                }

                counter = 0;

                while (countNumOfPaths != 2)
                {


                    Thread.Sleep(900); // assume that it represents the speed of the AUV which is in our case = 3 m/s as each meter equal to 300 seconds in thread.sleep()  

                    if (auv0Genetic.CancellationPending)
                    {
                        e.Cancel = true;
                        return;
                    }


                    if (forward)
                    {


                        if (counter == xPoints.Length - 1)
                        {

                            backward = true;

                            forward = false;

                            countNumOfPaths++;


                        }


                        else
                        {

                            auv[0].auvX = xPoints[counter];

                            auv[0].auvY = yPoints[counter];

                            counter++;

                        }


                    }

                    if (backward)
                    {

                        if (counter == 0)
                        {

                            backward = false;

                            forward = true;

                            countNumOfPaths++;

                        }

                        else
                        {

                            auv[0].auvX = xPoints[counter];


                            auv[0].auvY = yPoints[counter];


                            counter--;
                        }

                    }



                    //////////////////////// Draw ///////////////////////////

                    iSetupDisplay = 0;

                    if (iSetupDisplay != -1)
                    {
                        iSetupDisplay += 10;
                        if (iSetupDisplay >= topology.Width)
                            iSetupDisplay = -1;
                        topology.Refresh();
                    }


                    /////////////////////////////////////////////////////////

                }



            }

        }

问题是工人只运行一次,然后我停止执行并出现以下错误:

此 BackgroundWorker 当前正忙,无法运行多个任务 同时。

注意:我每次都尝试创建新的后台工作人员,但它不能正常工作,并且在我声明 50x4 后台工作人员时我得到了执行没有响应!!。

后台worker注册如下:

private System.ComponentModel.BackgroundWorker auv0Genetic;
private System.ComponentModel.BackgroundWorker auv1Genetic;
private System.ComponentModel.BackgroundWorker auv2Genetic;
private System.ComponentModel.BackgroundWorker auv3Genetic;



this.auv0Genetic = new System.ComponentModel.BackgroundWorker();
this.auv1Genetic = new System.ComponentModel.BackgroundWorker();
this.auv2Genetic = new System.ComponentModel.BackgroundWorker();
this.auv3Genetic = new System.ComponentModel.BackgroundWorker();

【问题讨论】:

  • 我不会为此使用 BackgroundWorker,而是使用 Task.Run 来启动 4 个作业。此外,函数末尾的代码确实应该在 lock 语句中,您有多个线程同时更新共享号码。
  • 那么如何应用你的答案,我知道使用后台工作者的方式:(你能帮我修改它们吗?!!
  • 你的主循环刚刚开始,没有等待 BackgroundWorkers 完成......
  • @C.Gonzalez : 如何让这个循环等待后台工作人员的每次迭代?

标签: c# multithreading backgroundworker cross-thread


【解决方案1】:

将您的原始示例转换为使用 TPL,您的代码将如下所示。

CancellationTokenSource cancelSource = new CancellationTokenSource();

public void Cancel() {
    cancelSource.Cancel();
}

public async Task Genetic_Algorithm(List<int[,]> population) {
    cancelSource = new CancellationTokenSource();
    DateTime startT = DateTime.Now.Date;
    double[,] FitnessValue = new double[6, 2]; // for all five chromosome we store two Values the Fitness Value and the Fitness Ratio
    int[] RouletteWheel = new int[6];
    int round = 0;
    for (geneticIteration = 0; geneticIteration < 50; geneticIteration++) {
        round = geneticIteration + 1;
        // Calculate the fitness Function and the Fitness Ratio
        await FitnessFunctionAsync(population, cancelSource.Token); // Fitness Function
    }
    MessageBox.Show("Press Again");
} 

public Task FitnessFunctionAsync(List<int[,]> population, CancellationToken cancelToken = default(CancellationToken)) {
    extractPath(population, geneticIteration);

    var task0 = RunAuv0GeneticAsync(cancelToken); // start obj # 1
    var task1 = RunAuv1GeneticAsync(cancelToken); // start obj # 2
    var task2 = RunAuv2GeneticAsync(cancelToken); // start obj # 3
    var task3 = RunAuv3GeneticAsync(cancelToken); // start obj # 4

    return Task.WhenAll(task0, task1, task2, task3);
}

在这个假设的示例中,后台工作的 do 工作方法也将被转换为异步。

例如

async Task RunAuv0GeneticAsync(CancellationToken cancelToken = default(CancellationToken)) {
    //Code removed for brevity
    countNumOfPaths = 0;

    //...code removed for brevity

    int counter = 0;

    for (int i = 0; i < 6; i++) {

        //...code removed for brevity

        counter = 0;

        while (countNumOfPaths != 2) {
            await Task.Delay(900);
            if (cancelToken != null && cancelToken.IsCancellationRequested) {
                return;
            }

            //...code removed for brevity;
        }

        //...code removed for brevity
    }
}

这样每次迭代都会等待对FitnessFunction 的每次调用。

【讨论】:

  • 很好,我会尝试但我有 VS 2010 .. 那么如何使用你的答案?
  • 什么是必要的声明,因为我在“RunAuv0GeneticAsync”、“WhenAll()”和 Task.Delay()...或在我放置所有需要的参考资料时缺少参考资料。我已经切换到 VS 2012 ...
  • @Rose 确保您拥有必要的命名空间System.Threading.Tasks,以便能够使用Taskasync/await
  • @Rose 您能否澄清一下FitnessFunction 中的工作人员是同时执行还是按顺序执行?
  • @Rose 好的,那么我使用Task.WhenAll 的建议是正确的。我不确定我是否明白你想要什么。
【解决方案2】:

如 cmets 中所述,使用 BackgroundWorker 协调不同的工作项很棘手,使用 Task 更容易。

一个最小的示例如下,循环的每次迭代都使用 Task.WaitAll() 来确保在开始新批次之前完成工作。

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
using System.Diagnostics;

namespace TaskExample
{
    public partial class Form1 : Form
    {
        //BackgroundWorker bw01, bw02, bw03, bw04;
        const int nmbRuns = 10;

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            for (int cnt = 0; cnt < nmbRuns; cnt++)
            {
                List<Task> allTasks = new List<Task>();
                List<int> elements = new List<int>() { 0, 1, 2, 3 };
                foreach (int i in elements)
                {
                    Task t = Task.Run(() => Work(i));
                    //Task t = Task.Run(() => { Task.Delay(i + 1000); Debug.WriteLine(i + " started"); });
                    allTasks.Add(t);
                }
                Debug.WriteLine("All workers started");
                Task.WaitAll(allTasks.ToArray());
                Debug.WriteLine("All workers finished run " + cnt);
            }
            Debug.WriteLine("All done.");
        }


        private async Task<bool> Work(int id)
        {
            Debug.WriteLine(id + " awaiting.");
            await Task.Delay(1000 * id);
            Debug.WriteLine(id + " finished waiting.");
            return true;
        }

    }
}

【讨论】:

  • 我提出了一种不同的方法,而不是对您的代码进行简单的修复。如果您确实需要使用 Backgroundworker,则需要在 for(genetic ...特定 bw 完成并使用 AutoResetEevents 例如。
  • 嗨,我在 Task.Run 和 .work() 上遇到错误--> 未识别!!
  • @C.Gonzalez 您将阻塞调用.WaitAll 与可能导致死锁的异步调用混合在一起。此外,Work 已经返回了一个任务,因此实际上没有必要将它包装在一个调用 allTasks.Add(Work(i))Task.Run
  • 同意不必要的包装。关于死锁,那是 OP 来解决的,对吧?他/她正在寻找一种方法来同步 4 个作业,并且在所有四个作业都在一个循环内完成之前让它们继续进行。
猜你喜欢
  • 1970-01-01
  • 2022-07-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-14
  • 1970-01-01
相关资源
最近更新 更多