Free cookie consent management tool by TermsFeed Policy Generator

Ignore:
Timestamp:
08/14/18 10:44:53 (6 years ago)
Author:
abeham
Message:

#2457: updated to trunk r15861

Location:
branches/2457_ExpertSystem/HeuristicLab.Optimization
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • branches/2457_ExpertSystem/HeuristicLab.Optimization

  • branches/2457_ExpertSystem/HeuristicLab.Optimization/3.3/MetaOptimizers/Experiment.cs

    r15330 r16075  
    11#region License Information
    22/* HeuristicLab
    3  * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
     3 * Copyright (C) 2002-2018 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
    44 *
    55 * This file is part of HeuristicLab.
     
    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;
    113     private ManualResetEventSlim allOptimizerFinished; // this indicates that all started optimizers have been paused or stopped
     123
     124    // track already started optimizers (.StartAsync does not set the executionstate immediately)
     125    // and to avoid restarting optimizers that were manually paused/stopped by the user
     126    private readonly IDictionary<IOptimizer, Task> startedOptimizers = new Dictionary<IOptimizer, Task>();
     127    private IEnumerable<IOptimizer> StartableOptimizers {
     128      get {
     129        return Optimizers
     130          .Where(x => x.ExecutionState == ExecutionState.Prepared || x.ExecutionState == ExecutionState.Paused)
     131          .Where(o => !startedOptimizers.ContainsKey(o));  // all startable optimizers that were not startet yet
     132      }
     133    }
    114134
    115135    public Experiment()
     
    155175      experimentStarted = original.experimentStarted;
    156176      experimentStopped = original.experimentStopped;
     177      numberOfWorkers = original.numberOfWorkers;
    157178      Initialize();
    158179    }
     
    192213      if ((ExecutionState != ExecutionState.Prepared) && (ExecutionState != ExecutionState.Paused))
    193214        throw new InvalidOperationException(string.Format("Start not allowed in execution state \"{0}\".", ExecutionState));
    194       if (Optimizers.Count == 0) return;
     215
     216      startedOptimizers.Clear();
     217      if (!StartableOptimizers.Any()) return;
    195218
    196219      experimentStarted = true;
    197220      experimentStopped = false;
    198       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;
    205       }
    206 
    207       allOptimizerFinished.Wait();
     221
     222      using (var availableWorkers = new SemaphoreSlim(NumberOfWorkers, NumberOfWorkers)) {
     223        while (StartableOptimizers.Any()) {
     224          try {
     225            availableWorkers.Wait(cancellationToken);
     226            var optimizer = StartableOptimizers.FirstOrDefault();
     227            if (experimentStopped || !experimentStarted || optimizer == null) break;
     228
     229            var startedTask = optimizer.StartAsync(cancellationToken).ContinueWith(async t => {
     230              availableWorkers.Release(); // is guaranteed to be not disposed yet because Task.WaitAll blocks before the end of the using
     231              await t; // trigger a potential exception on the optimizerTask
     232            });
     233            startedOptimizers.Add(optimizer, startedTask.Unwrap()); // unwrap task because lambda of .ContinueWith is async
     234          } catch (InvalidOperationException) { } catch (OperationCanceledException) { }
     235        }
     236
     237        Task.WaitAll(startedOptimizers.Values.ToArray()); // retrieve exeptions of the asyncrounously started optimizer
     238      }
    208239    }
    209240    public async Task StartAsync() { await StartAsync(CancellationToken.None); }
     
    220251      foreach (IOptimizer optimizer in Optimizers.Where(x => x.ExecutionState == ExecutionState.Started)) {
    221252        // a race-condition may occur when the optimizer has changed the state by itself in the meantime
    222         try { optimizer.Pause(); } catch (InvalidOperationException) { }
     253        try { optimizer.Pause(); } catch (InvalidOperationException) { } catch (NotSupportedException) { }
    223254      }
    224255    }
     
    258289    public event EventHandler Prepared;
    259290    private void OnPrepared() {
     291      if (ExecutionState == ExecutionState.Prepared) return;
    260292      ExecutionState = ExecutionState.Prepared;
    261293      EventHandler handler = Prepared;
     
    264296    public event EventHandler Started;
    265297    private void OnStarted() {
     298      if (ExecutionState == ExecutionState.Started) return;
    266299      ExecutionState = ExecutionState.Started;
    267300      EventHandler handler = Started;
     
    270303    public event EventHandler Paused;
    271304    private void OnPaused() {
     305      if (ExecutionState == ExecutionState.Paused) return;
    272306      ExecutionState = ExecutionState.Paused;
    273307      EventHandler handler = Paused;
     
    276310    public event EventHandler Stopped;
    277311    private void OnStopped() {
     312      if (ExecutionState == ExecutionState.Stopped) return;
    278313      ExecutionState = ExecutionState.Stopped;
    279314      EventHandler handler = Stopped;
     
    372407    }
    373408    private void optimizer_Paused(object sender, EventArgs e) {
    374       lock (locker)
    375         if (Optimizers.All(x => x.ExecutionState != ExecutionState.Started)) {
    376           OnPaused();
    377           allOptimizerFinished.Set();
    378         }
     409      UpdateExecutionState();
    379410    }
    380411    private void optimizer_Prepared(object sender, EventArgs e) {
    381       lock (locker)
    382         if (Optimizers.All(x => x.ExecutionState == ExecutionState.Prepared)) OnPrepared();
     412      UpdateExecutionState();
    383413    }
    384414    private void optimizer_Started(object sender, EventArgs e) {
     
    387417    }
    388418    private void optimizer_Stopped(object sender, EventArgs e) {
     419      UpdateExecutionState();
     420    }
     421    private void UpdateExecutionState() {
     422      // Execution states of the Experiment are determined using the following _basic_ rules:
     423      //   if any Optimizer is Started      => Experiment is Started  (2. if)
     424      //   if any Optimizer is Paused       => Experiment is Paused   (3. if)
     425      //   if any Optimizer is Prepared     => Experiment is Prepared (5. if)
     426      //   else (all Optimizer are Stopped) => Experiment is Stopped  (6. if)
     427      // Additional there are two extra rules:
     428      //   if the Experiment is running and there are still optimizers that can be started => keep the Experiment Running (1. if)
     429      //   if experiment-stop is pending: Stop Experiment even if there are still Prepared Optimizer               (4. if)
     430
    389431      lock (locker) {
    390         if (experimentStopped) {
    391           if (Optimizers.All(x => (x.ExecutionState == ExecutionState.Stopped) || (x.ExecutionState == ExecutionState.Prepared))) {
    392             OnStopped();
    393             allOptimizerFinished.Set();
    394           }
    395         } else {
    396           if (experimentStarted && Optimizers.Any(x => (x.ExecutionState == ExecutionState.Prepared) || (x.ExecutionState == ExecutionState.Paused))) return;
    397           else if (Optimizers.All(x => x.ExecutionState == ExecutionState.Stopped)) {
    398             OnStopped();
    399             allOptimizerFinished.Set();
    400           } else if (Optimizers.Any(x => (x.ExecutionState == ExecutionState.Prepared) || (x.ExecutionState == ExecutionState.Paused)) && Optimizers.All(o => o.ExecutionState != ExecutionState.Started)) {
    401             OnPaused();
    402             allOptimizerFinished.Set();
    403           }
    404         }
    405       }
    406     }
     432        // 1. experiment is running & further startable optimizers are available => continue executing
     433        if (experimentStarted && StartableOptimizers.Any())
     434          return;
     435
     436        // 2. any optimizer is running => continue executing
     437        if (Optimizers.Any(x => x.ExecutionState == ExecutionState.Started))
     438          return;
     439
     440        experimentStarted = false;
     441        // 3. any optimizer is paused => experiment paused
     442        if (Optimizers.Any(x => x.ExecutionState == ExecutionState.Paused))
     443          OnPaused();
     444
     445        // 4. stop pending & all optimizers either stopped or prepared => experiment stopped
     446        else if (experimentStopped)
     447          OnStopped();
     448
     449        // 5. any optimizer prepared => experiment prepared
     450        else if (Optimizers.Any(x => x.ExecutionState == ExecutionState.Prepared))
     451          OnPrepared();
     452
     453        // 6. (else) all optimizers stopped
     454        else
     455          OnStopped();
     456      }
     457    }
     458
    407459    private void optimizer_Runs_CollectionReset(object sender, CollectionItemsChangedEventArgs<IRun> e) {
    408460      lock (runsLocker) {
Note: See TracChangeset for help on using the changeset viewer.