Free cookie consent management tool by TermsFeed Policy Generator

Ignore:
Timestamp:
08/22/17 14:08:52 (7 years ago)
Author:
pfleck
Message:

#2822 Added parallel execution support for Experiment (similar to CrossValidation).

  • Fixed race-condition in BasicAlgorithm (potential NullReference of CancellationTokenSource).
  • Fixed race-condition in BatchRun (calling .Stop potentially fires both OnStopped and OnPaused).
Location:
branches/ParallelExperiment/HeuristicLab.Optimization/3.3
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • branches/ParallelExperiment/HeuristicLab.Optimization/3.3/Algorithms/BasicAlgorithm.cs

    r15302 r15337  
    8080      try {
    8181        Run((object)cancellationTokenSource.Token);
    82       }
    83       catch (OperationCanceledException) {
    84       }
    85       catch (AggregateException ae) {
     82      } catch (OperationCanceledException) {
     83      } catch (AggregateException ae) {
    8684        OnExceptionOccurred(ae.InnerExceptions.SingleOrDefault() ?? ae);
    87       }
    88       catch (Exception e) {
     85      } catch (Exception e) {
    8986        OnExceptionOccurred(e);
    9087      }
     
    104101      base.Pause();
    105102      pausePending = true;
    106       CancellationTokenSource.Cancel();
     103      CancellationTokenSource?.Cancel();
    107104    }
    108105
     
    112109      base.Stop();
    113110      if (ExecutionState == ExecutionState.Paused) OnStopped();
    114       else CancellationTokenSource.Cancel();
     111      else CancellationTokenSource?.Cancel();
    115112    }
    116113
     
    127124        initialized = true;
    128125        Run(cancellationToken);
    129       }
    130       finally {
     126      } finally {
    131127        timer.Elapsed -= new System.Timers.ElapsedEventHandler(timer_Elapsed);
    132128        timer.Stop();
  • branches/ParallelExperiment/HeuristicLab.Optimization/3.3/MetaOptimizers/BatchRun.cs

    r15287 r15337  
    258258        if (ExecutionState == ExecutionState.Paused || ExecutionState == ExecutionState.Stopped) break;
    259259        Optimizer.Prepare();
     260        if (ExecutionState == ExecutionState.Paused || ExecutionState == ExecutionState.Stopped) break;
    260261      }
    261262    }
     
    271272      if (Optimizer.ExecutionState != ExecutionState.Started) return;
    272273      // a race-condition may occur when the optimizer has changed the state by itself in the meantime
    273       try { Optimizer.Pause(); } catch (InvalidOperationException) { }
     274      try { Optimizer.Pause(); } catch (InvalidOperationException) { } catch (NotSupportedException) { }
    274275    }
    275276    public void Stop() {
     
    385386    }
    386387    private void Optimizer_Prepared(object sender, EventArgs e) {
    387       if (batchRunAction == BatchRunAction.Prepare || ExecutionState == ExecutionState.Stopped) {
     388      if (batchRunAction == BatchRunAction.Prepare/* || ExecutionState == ExecutionState.Stopped*/) {
    388389        ExecutionTime = TimeSpan.Zero;
    389390        runsExecutionTime = TimeSpan.Zero;
  • branches/ParallelExperiment/HeuristicLab.Optimization/3.3/MetaOptimizers/Experiment.cs

    r15328 r15337  
    9797    }
    9898
     99    [Storable]
     100    private int numberOfWorkers = 1;
     101    public int NumberOfWorkers {
     102      get { return numberOfWorkers; }
     103      set {
     104        if (value < 1) throw new ArgumentException("Number of Workers must not be lower than one.");
     105        numberOfWorkers = value;
     106      }
     107    }
     108
    99109    public IEnumerable<IOptimizer> NestedOptimizers {
    100110      get {
     
    111121    private bool experimentStarted = false;
    112122    private bool experimentStopped = false;
     123
    113124    private ManualResetEventSlim allOptimizerFinished; // this indicates that all started optimizers have been paused or stopped
     125    private SemaphoreSlim availableWorkers; // limits the number of concurrent optimizer executions
    114126
    115127    public Experiment()
     
    155167      experimentStarted = original.experimentStarted;
    156168      experimentStopped = original.experimentStopped;
     169      numberOfWorkers = original.numberOfWorkers;
    157170      Initialize();
    158171    }
     
    189202      Start(CancellationToken.None);
    190203    }
     204
    191205    public void Start(CancellationToken cancellationToken) {
    192206      if ((ExecutionState != ExecutionState.Prepared) && (ExecutionState != ExecutionState.Paused))
     
    197211      experimentStopped = false;
    198212      allOptimizerFinished = new ManualResetEventSlim(false);
    199 
    200       IOptimizer optimizer;
    201       while ((optimizer = Optimizers.FirstOrDefault(x => (x.ExecutionState == ExecutionState.Prepared) || (x.ExecutionState == ExecutionState.Paused))) != null) {
    202         // a race-condition may occur when the optimizer has changed the state by itself in the meantime
    203         try { optimizer.Start(cancellationToken); } catch (InvalidOperationException) { }
    204         if (ExecutionState == ExecutionState.Paused || ExecutionState == ExecutionState.Stopped) break;
     213      availableWorkers = new SemaphoreSlim(NumberOfWorkers, NumberOfWorkers);
     214
     215      var runnableOptimizers = Optimizers.Where(o => o.ExecutionState == ExecutionState.Prepared || o.ExecutionState == ExecutionState.Paused).ToList();
     216      if (!runnableOptimizers.Any()) return;
     217
     218      while (runnableOptimizers.Any()) {
     219        try {
     220          availableWorkers.Wait(cancellationToken); // an optimizer was pause/stopped previously
     221          if (experimentStopped || !experimentStarted) break;
     222          // some optimizers might be started manually somewhere else
     223          runnableOptimizers.RemoveAll(o => !(o.ExecutionState == ExecutionState.Prepared || o.ExecutionState == ExecutionState.Paused));
     224          var optimizer = runnableOptimizers.FirstOrDefault();
     225          runnableOptimizers.Remove(optimizer);
     226          optimizer?.StartAsync(cancellationToken);
     227        } catch (InvalidOperationException) { } catch (OperationCanceledException) { }
    205228      }
    206229
     
    220243      foreach (IOptimizer optimizer in Optimizers.Where(x => x.ExecutionState == ExecutionState.Started)) {
    221244        // a race-condition may occur when the optimizer has changed the state by itself in the meantime
    222         try { optimizer.Pause(); } catch (InvalidOperationException) { }
     245        try { optimizer.Pause(); } catch (InvalidOperationException) { } catch (NotSupportedException) { }
    223246      }
    224247    }
     
    273296      EventHandler handler = Paused;
    274297      if (handler != null) handler(this, EventArgs.Empty);
     298      allOptimizerFinished.Set();
    275299    }
    276300    public event EventHandler Stopped;
     
    279303      EventHandler handler = Stopped;
    280304      if (handler != null) handler(this, EventArgs.Empty);
     305      allOptimizerFinished.Set();
    281306    }
    282307    public event EventHandler<EventArgs<Exception>> ExceptionOccurred;
     
    372397    }
    373398    private void optimizer_Paused(object sender, EventArgs e) {
    374       lock (locker)
     399      lock (locker) {
     400        if (availableWorkers.CurrentCount < NumberOfWorkers)
     401          availableWorkers.Release();
    375402        if (Optimizers.All(x => x.ExecutionState != ExecutionState.Started)) {
    376403          OnPaused();
    377           allOptimizerFinished.Set();
    378         }
     404        }
     405      }
    379406    }
    380407    private void optimizer_Prepared(object sender, EventArgs e) {
     
    388415    private void optimizer_Stopped(object sender, EventArgs e) {
    389416      lock (locker) {
     417        if (availableWorkers.CurrentCount < NumberOfWorkers)
     418          availableWorkers.Release();
    390419        if (experimentStopped) {
    391420          if (Optimizers.All(x => (x.ExecutionState == ExecutionState.Stopped) || (x.ExecutionState == ExecutionState.Prepared))) {
    392421            OnStopped();
    393             allOptimizerFinished.Set();
    394422          }
    395423        } else {
     
    397425          else if (Optimizers.All(x => x.ExecutionState == ExecutionState.Stopped)) {
    398426            OnStopped();
    399             allOptimizerFinished.Set();
    400427          } else if (Optimizers.Any(x => (x.ExecutionState == ExecutionState.Prepared) || (x.ExecutionState == ExecutionState.Paused)) && Optimizers.All(o => o.ExecutionState != ExecutionState.Started)) {
    401428            OnPaused();
    402             allOptimizerFinished.Set();
    403429          }
    404430        }
Note: See TracChangeset for help on using the changeset viewer.