JobList class

Works off tasks (jobs) in parallel in the background with a specified number of worker threads to optimally use the computing power of multi-core processors.

Das Problem

Mit mehrkernigen Prozessoren steigt theoretisch auch die Rechenleistung fast linear an – aber nur, wenn die Aufgaben auch parallelisiert werden können. Oft werden mehrere gleichartige Aufgaben nacheinander durchgeführt, wie z. B. das Erstellen von Berichten oder Diagrammen in verschiedenen Ansichten. Die Reihenfolge dieser Arbeiten ist in der Regel egal, also kann man sie oft auch gleichzeitig ausführen. Selbst dei einer geringen Anzahl physischer CPUs oder Kerne kann eine Parallelisierung der Aufgaben die Gesamtzeit verringern, wenn die Aufgaben häufige Wartepausen einlegen, in denen z. B. auf Netzwerkantworten gewartet wird.

Die Lösung

Die JobList-Klasse vereinfacht die parallele Ausführung solcher Aufgaben enorm. Die Verwendung ähnelt ein bisschen der BackgroundWorker-Klasse, aber die gesamte Job-Listenverwaltung ist auch schon mit drin. Jeder Aufgabentyp besteht aus einer Klasse, die von der abstrakten Basisklasse Job abgeleitet ist. Jeder Aufgabeninstanz können über ihren Konstruktor individuelle Anweisungen wie Dateinamen oder Selektionskriterien mitgegeben werden. Die Job-Instanzen werden dann nur noch einer JobList-Instanz hinzugefügt und schon beginnt die Bearbeitung der Aufgaben. Sobald eine Aufgabe abgeschlossen ist, wird die nächste wartende Aufgabe in einem freien Worker-Thread gestartet. Um eine Überlastung zu vermeiden, ist die Anzahl der Threads begrenzt und auf die doppelte Anzahl der verfügbaren CPU-Kerne voreingestellt (konfigurierbar). So wie weitere Aufgaben anfallen, können diese einfach weiter der JobList hinzugefügt werden, auch wenn noch nicht alle anstehenden Aufgaben abgeschlossen sind. Wenn das der Fall ist, wird ein Ereignis ausgelöst, auf das die Benutzeroberfläche mit einer Meldung oder Anzeige reagieren kann. Zwischenmeldungen zum Fortschritt sind ebenfalls verfügbar.

Compatibility: .NET Version 2.0 or newer

Beispiel

Der folgende Beispielcode zeigt, wie die JobList-Klasse verwendet werden kann. Es werden mehrere Diagramme parallel nach verschiedenen Spezifikationsdateien in verschiedenen Größen erstellt. Die eigentliche Arbeit wird in der PlotJob.DoWork-Methode implementiert.

class Program
{
    // …
   
    private void GenerateGraphs(IEnumerable<PlotSpec> specs)
    {
        // Create the JobList instance
        JobList plotJobs = new JobList();
        // Know when one of the jobs fails
        plotJobs.JobError += new EventHandler<JobListErrorEventArgs>(plotJobs_JobError);
        // Add all jobs to the list to have them worked off
        foreach (var spec in specs)
        {
            Job job = new PlotJob(spec.FileName, spec.CustomSize);
            plotJobs.AppendJob(job);
        }
        // Wait for the last one to complete
        plotJobs.JoinAll();
    }

    private void plotJobs_JobError(object sender, JobListErrorEventArgs e)
    {
        // Just print out the full error details for now
        Console.Error.WriteLine(e.Error.ToString());
    }
}

// This class defines what a "Plot Job" is about and what to do.
// There can be other inherited classes that do other work and you can add
// any of them to one single JobList.
class PlotJob : Job
{
    private string fileName;
    private Size customSize;

    // Initialises a new instance of the PlotJob and sets the parameters of
    // the work to do.
    public PlotJob(string fileName, Size customSize)
    {
        this.fileName = fileName;
        this.customSize = customSize;
    }

    // This method does the work. It is called by the JobList on a worker thread.
    public override void DoWork()
    {
        Common.PlotBySpec(fileName, customSize, true);
        // Just return when you're finished, the next pending job will start
        // right away, if there is one left.
    }
}

Download

JobList.cs9.0 KiBQuelltext der JobList-Klasse

Änderungen

2012Feb9
  • Fehler werden über das JobError-Ereignis gemeldet.
  • Anzahl der Worker mit doppelter CPU-Anzahl statt 3 vorbelegt
  • JoinAll-Methode hinzugefügt: Zeitlich begrenztes Warten auf den Abschluss aller Jobs.
  • Code-Dokumentation erweitert.

Licence and terms of use

Copying and distribution of this file, with or without modification, are permitted provided the copyright notice and this notice are preserved. This file is offered as-is, without any warranty. (GNU All-Permissive licence)

Statistic data

  • Created on 2008-11-02, updated on 2012-02-09.
  • Ca. 150 lines of code, estimated development costs: 150 - 600 €