Free cookie consent management tool by TermsFeed Policy Generator

Ignore:
Timestamp:
01/12/18 14:24:16 (6 years ago)
Author:
abeham
Message:

#1614: merged trunk into branch

Location:
branches/GeneralizedQAP/HeuristicLab.Optimization
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • branches/GeneralizedQAP/HeuristicLab.Optimization

  • branches/GeneralizedQAP/HeuristicLab.Optimization/3.3/MetaOptimizers/Experiment.cs

    r15603 r15605  
    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.
     
    9393    }
    9494
     95    [Storable]
     96    private int numberOfWorkers = 1;
     97    public int NumberOfWorkers {
     98      get { return numberOfWorkers; }
     99      set {
     100        if (value < 1) throw new ArgumentException("Number of Workers must not be lower than one.");
     101        numberOfWorkers = value;
     102      }
     103    }
     104
    95105    public IEnumerable<IOptimizer> NestedOptimizers {
    96106      get {
     
    107117    private bool experimentStarted = false;
    108118    private bool experimentStopped = false;
    109     private readonly ManualResetEventSlim allOptimizerFinished = new ManualResetEventSlim(false); // this indicates that all started optimizers have been paused or stopped
     119
     120    // track already started optimizers (.StartAsync does not set the executionstate immediately)
     121    // and to avoid restarting optimizers that were manually paused/stopped by the user
     122    private readonly IDictionary<IOptimizer, Task> startedOptimizers = new Dictionary<IOptimizer, Task>();
     123    private IEnumerable<IOptimizer> StartableOptimizers {
     124      get {
     125        return Optimizers
     126          .Where(x => x.ExecutionState == ExecutionState.Prepared || x.ExecutionState == ExecutionState.Paused)
     127          .Where(o => !startedOptimizers.ContainsKey(o));  // all startable optimizers that were not startet yet
     128      }
     129    }
    110130
    111131    public Experiment()
     
    151171      experimentStarted = original.experimentStarted;
    152172      experimentStopped = original.experimentStopped;
     173      numberOfWorkers = original.numberOfWorkers;
    153174      Initialize();
    154175    }
     
    188209      if ((ExecutionState != ExecutionState.Prepared) && (ExecutionState != ExecutionState.Paused))
    189210        throw new InvalidOperationException(string.Format("Start not allowed in execution state \"{0}\".", ExecutionState));
    190       if (!Optimizers.Any(x => x.ExecutionState == ExecutionState.Prepared || x.ExecutionState == ExecutionState.Paused)) return;
     211
     212      startedOptimizers.Clear();
     213      if (!StartableOptimizers.Any()) return;
    191214
    192215      experimentStarted = true;
    193216      experimentStopped = false;
    194       allOptimizerFinished.Reset();
    195       IOptimizer optimizer;
    196       while ((optimizer = Optimizers.FirstOrDefault(x => x.ExecutionState == ExecutionState.Prepared || x.ExecutionState == ExecutionState.Paused)) != null) {
    197         // a race-condition may occur when the optimizer has changed the state by itself in the meantime
    198         try { optimizer.Start(cancellationToken); } catch (InvalidOperationException) { }
    199         if (ExecutionState == ExecutionState.Paused || ExecutionState == ExecutionState.Stopped) break;
    200       }
    201       allOptimizerFinished.Wait();
     217
     218      using (var availableWorkers = new SemaphoreSlim(NumberOfWorkers, NumberOfWorkers)) {
     219        while (StartableOptimizers.Any()) {
     220          try {
     221            availableWorkers.Wait(cancellationToken);
     222            var optimizer = StartableOptimizers.FirstOrDefault();
     223            if (experimentStopped || !experimentStarted || optimizer == null) break;
     224
     225            var startedTask = optimizer.StartAsync(cancellationToken).ContinueWith(async t => {
     226              availableWorkers.Release(); // is guaranteed to be not disposed yet because Task.WaitAll blocks before the end of the using
     227              await t; // trigger a potential exception on the optimizerTask
     228            });
     229            startedOptimizers.Add(optimizer, startedTask.Unwrap()); // unwrap task because lambda of .ContinueWith is async
     230          } catch (InvalidOperationException) { } catch (OperationCanceledException) { }
     231        }
     232
     233        Task.WaitAll(startedOptimizers.Values.ToArray()); // retrieve exeptions of the asyncrounously started optimizer
     234      }
    202235    }
    203236    public async Task StartAsync() { await StartAsync(CancellationToken.None); }
     
    214247      foreach (IOptimizer optimizer in Optimizers.Where(x => x.ExecutionState == ExecutionState.Started)) {
    215248        // a race-condition may occur when the optimizer has changed the state by itself in the meantime
    216         try { optimizer.Pause(); } catch (InvalidOperationException) { }
     249        try { optimizer.Pause(); } catch (InvalidOperationException) { } catch (NotSupportedException) { }
    217250      }
    218251    }
     
    249282    public event EventHandler Prepared;
    250283    private void OnPrepared() {
     284      if (ExecutionState == ExecutionState.Prepared) return;
    251285      ExecutionState = ExecutionState.Prepared;
    252286      EventHandler handler = Prepared;
     
    255289    public event EventHandler Started;
    256290    private void OnStarted() {
     291      if (ExecutionState == ExecutionState.Started) return;
    257292      ExecutionState = ExecutionState.Started;
    258293      EventHandler handler = Started;
     
    261296    public event EventHandler Paused;
    262297    private void OnPaused() {
     298      if (ExecutionState == ExecutionState.Paused) return;
    263299      ExecutionState = ExecutionState.Paused;
    264       allOptimizerFinished.Set();
    265300      EventHandler handler = Paused;
    266301      if (handler != null) handler(this, EventArgs.Empty);
     
    268303    public event EventHandler Stopped;
    269304    private void OnStopped() {
     305      if (ExecutionState == ExecutionState.Stopped) return;
    270306      ExecutionState = ExecutionState.Stopped;
    271       allOptimizerFinished.Set();
    272307      EventHandler handler = Stopped;
    273308      if (handler != null) handler(this, EventArgs.Empty);
     
    353388    }
    354389    private void optimizer_Paused(object sender, EventArgs e) {
    355       lock (locker)
    356         if (Optimizers.All(x => x.ExecutionState != ExecutionState.Started)) OnPaused();
     390      UpdateExecutionState();
    357391    }
    358392    private void optimizer_Prepared(object sender, EventArgs e) {
    359       lock (locker)
    360         if (Optimizers.All(x => x.ExecutionState == ExecutionState.Prepared)) OnPrepared();
     393      UpdateExecutionState();
    361394    }
    362395    private void optimizer_Started(object sender, EventArgs e) {
     
    365398    }
    366399    private void optimizer_Stopped(object sender, EventArgs e) {
     400      UpdateExecutionState();
     401    }
     402    private void UpdateExecutionState() {
     403      // Execution states of the Experiment are determined using the following _basic_ rules:
     404      //   if any Optimizer is Started      => Experiment is Started  (2. if)
     405      //   if any Optimizer is Paused       => Experiment is Paused   (3. if)
     406      //   if any Optimizer is Prepared     => Experiment is Prepared (5. if)
     407      //   else (all Optimizer are Stopped) => Experiment is Stopped  (6. if)
     408      // Additional there are two extra rules:
     409      //   if the Experiment is running and there are still optimizers that can be started => keep the Experiment Running (1. if)
     410      //   if experiment-stop is pending: Stop Experiment even if there are still Prepared Optimizer               (4. if)
     411
    367412      lock (locker) {
    368         if (experimentStopped) {
    369           if (Optimizers.All(x => (x.ExecutionState == ExecutionState.Stopped) || (x.ExecutionState == ExecutionState.Prepared))) OnStopped();
    370         } else {
    371           if (experimentStarted && Optimizers.Any(x => (x.ExecutionState == ExecutionState.Prepared) || (x.ExecutionState == ExecutionState.Paused))) return;
    372           else if (Optimizers.All(x => x.ExecutionState == ExecutionState.Stopped)) OnStopped();
    373           else if (Optimizers.Any(x => (x.ExecutionState == ExecutionState.Prepared) || (x.ExecutionState == ExecutionState.Paused)) && Optimizers.All(o => o.ExecutionState != ExecutionState.Started)) OnPaused();
    374         }
    375       }
    376     }
     413        // 1. experiment is running & further startable optimizers are available => continue executing
     414        if (experimentStarted && StartableOptimizers.Any())
     415          return;
     416
     417        // 2. any optimizer is running => continue executing
     418        if (Optimizers.Any(x => x.ExecutionState == ExecutionState.Started))
     419          return;
     420
     421        experimentStarted = false;
     422        // 3. any optimizer is paused => experiment paused
     423        if (Optimizers.Any(x => x.ExecutionState == ExecutionState.Paused))
     424          OnPaused();
     425
     426        // 4. stop pending & all optimizers either stopped or prepared => experiment stopped
     427        else if (experimentStopped)
     428          OnStopped();
     429
     430        // 5. any optimizer prepared => experiment prepared
     431        else if (Optimizers.Any(x => x.ExecutionState == ExecutionState.Prepared))
     432          OnPrepared();
     433
     434        // 6. (else) all optimizers stopped
     435        else
     436          OnStopped();
     437      }
     438    }
     439
    377440    private void optimizer_Runs_CollectionReset(object sender, CollectionItemsChangedEventArgs<IRun> e) {
    378441      lock (runsLocker) {
Note: See TracChangeset for help on using the changeset viewer.