How to use Task.run to perform the function of Do_

2019-09-20 15:52发布

问题:

I move 4 objects in parallel in a specific paths stored in a list of paths, when each of them complete one path(specific coordinates) it switches to another!.

I used 4 background workers to perform such a job in background and in each call each background worker should try 6 paths (chromosomes) extracted from an a text file and each path stored in different 6 lists and each list contains the coordinates for each path. The coordinates then converted to 2D points to perform projection and each path at a specific depth as the paths to move these objects on different layers using a projection technique i.e. ach object (worker) will be moved at different layer.

Each worker should move the object forward and backward using one path (chromosome) then switches to the next and it should finish the first attempt (path) completely before switch to next in order to calculate the time consumed and other factors such as "Fitness" function.

The following is an example on one the Do_Work() methods:

    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_auv_1 = 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_auv_1 != 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_auv_1++;
                        }
                        else
                        {
                            auv[0].auvX = xPoints[counter];
                            auv[0].auvY = yPoints[counter];

                            counter++;
                        }
                    }

                    if (backward)
                    {
                        if (counter == 0)
                        {
                            backward = false;
                            forward = true;
                            countNumOfPaths_auv_1++;
                        }
                        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();
                    }
                /////////////////////////////////////////////////////////
                }
        }

    }

I declared each background worker like this:

    auv0Genetic = new BackgroundWorker();

                    auv0Genetic.WorkerSupportsCancellation = true;

                    auv0Genetic.DoWork += new DoWorkEventHandler(auv0Genetic_DoWork);

                    auv0Genetic.RunWorkerCompleted += new 

RunWorkerCompletedEventHandler(auv0Genetic_RunWorkerCompleted);

I declared them in a loop that loops 250 times and call them inside this loop each time by calling another method that contains the following lines:

auv0Genetic.RunWorkerAsync(geneticIteration); // start AUV # 1

Problems :

There is no synchronization between the loop and the Do_Work() method i.e. the loop starts new iteration before the 4 backgrounds worker finishes their work completely where for each iteration there is a list contains 6 different paths (chromosomes) and each background worker should tries them before the next iteration with the new list. I need to stop the workers completely before going to the next iteration. I put a message box outside the loop and I do not get it appeared after the completion of the loop even after all the workers stop.

My Question Is:

I faced some problems with using background workers so I wondered if it is possible to use Task class instead, if so .. then how to use Task.run to perform the same job inside Do_Work() methods ?

回答1:

The main concept is:

public async Task WorkerStartedMethod()
{
    for(int i = 0; i<=250; i++)
    {
        List<Task> tasks = new List<Task>();
        tasks.add(Task.Run(auv0Genetic_DoWork));
        tasks.add(Task.Run(auv0Genetic_DoWork));
        tasks.add(Task.Run(auv0Genetic_DoWork));
        tasks.add(Task.Run(auv0Genetic_DoWork));
        tasks.add(Task.Run(auv0Genetic_DoWork));
        tasks.add(Task.Run(auv0Genetic_DoWork));
        await Task.WhenAll(tasks);
    }
}

However I have an assumption that "DoWork" method should be rewritten in case you need access to the UI thread. You should add dispatchers in all parts where you try change something on the UI.



回答2:

My Assumptions to be able to give an answer:

  • This uses objects with associated tasks as you sounded interested in using tasks and yes it will go much smoother than jerryrigging background workers.
  • I am going to assume that you understand your business logic and there is no need for me to.

  • I will focus on a way to process data in a uniform way with options to increase capacity.

  • Of course I am willing to amend and illuminate unclear areas.

  • This should be considered Psuedo Code, I did not compile this and with the missing ideas it would not compile. Some edits to fix small things may be needed as I was going for the big picture idea here not the details.

THE CODE

INCLUDES

The Includes you will need:

using System;
using System.Threading.Tasks;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Threading;
using System.Diagnostics;

PROCESSING LOOP

This is the main loop you could call this from a single background worker:

public void BeginProcess()
{
    //This is the limitation on threads/cpu usage
    var maxWorkers = 4;
    //You could tackle how to go through the loop many ways this was how I was doing it for a simple file transfer program so I didn't change the paradigm
    var currentWorker = 0;

    //This is the Worker List that will hold and then run our chromosome business logic
    var ChromosomeWorkers = new List<ChromWorker>();

    //I am not sure based on the code how you are running through this, but here is a population example
    foreach (var chromTemplate in ChromosomeTemplates)
    {

        var cw = new ChromWorker(/*pass in appropriate arrays etc*/);
        ChromosomeWorkers.Add(cw);


            //If the count of Running workers is less than Max Workers and we are not at the end of the list Continue starting them
        if (ChromosomeWorkers.Count(x => x.Running) < maxWorkers && currentWorker < ChromosomeWorkers.Count)
        {
            ChromosomeWorkers[currentWorker].Start();
            currentWorker++;
        }


    }


    //Transition from Creation to Pure Processing
    do
    {
        if (ChromosomeWorkers.Count(x => x.Running) < maxWorkers && currentWorker < ChromosomeWorkers.Count)
        {
            FilesToBeTransferred[currentWorker].Start();
            currentWorker++;
        }
        else
        {
            //If the workers are maxed then sleep for a bit on this thread
            Thread.Sleep(150);
        }
    }
    while (currentWorker < ChromosomeWorkers.Count);


}

WORKER CLASS

NOTE: There are a lot of other Task states you might have to account for like IsFaulted, etc. I wanted to keep this concise so I did not go into those cases but you might have to account for them.

This is the worker class which will do most of the footwork:

public class ChromWorker
{
    private Task _t;

    bool isConsumed = false;
    pathChromosom1 [,];
    string _Key = string.Empty;
    List<Tag> _Tags = new List<Tag>();

    public ChromWorker(/*Data that might be useful in your worker*/)
    {
        pathChromosom1 = inChromosomeArrays;


    }


    public bool Running
    {
        get
        {

            if (_t == null || _t.IsCompleted ) return false;

            return true;
        }
    }

    public bool Done
    {
        get
        {
            return _t != null && _t.IsCompleted;
        }
    }

    public bool Ready
    {
        get { return _t == null; }
    }

    public void Start()
    {
        _t = new Task(_Run);
        _t.Start();

    }

    private void _Run()
    {
        double tries = 0;
        bool Handled = false;
        while (!Handled && tries < Math.Pow(10, 6))
        {
            //Increase our giveup loop
            tries++;
            try
            {
                /* your Business logic */
                Handled = true;

            }
            catch (Exception e)
            {

                Console.WriteLine("Exception: {0} StackTrace: {1}", e.Message, e.StackTrace);
            }

        }

    }
}