Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Problems.ExternalEvaluation/3.4/Drivers/EvaluationServiceClient.cs @ 12706

Last change on this file since 12706 was 12012, checked in by ascheibe, 10 years ago

#2212 merged r12008, r12009, r12010 back into trunk

File size: 6.4 KB
RevLine 
[3872]1#region License Information
2/* HeuristicLab
[12012]3 * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
[3872]4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
[8298]23using System.IO;
24using Google.ProtocolBuffers;
[4722]25using HeuristicLab.Common;
[3872]26using HeuristicLab.Core;
[4068]27using HeuristicLab.Data;
28using HeuristicLab.Parameters;
[3872]29using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
30
31namespace HeuristicLab.Problems.ExternalEvaluation {
32  [Item("EvaluationServiceClient", "An RPC client that evaluates a solution.")]
33  [StorableClass]
34  public class EvaluationServiceClient : ParameterizedNamedItem, IEvaluationServiceClient {
[6470]35
[3872]36    public override bool CanChangeName { get { return false; } }
37    public override bool CanChangeDescription { get { return false; } }
38
[6470]39    #region Parameters
[3872]40    public IValueParameter<IEvaluationChannel> ChannelParameter {
41      get { return (IValueParameter<IEvaluationChannel>)Parameters["Channel"]; }
42    }
[3895]43    public IValueParameter<IntValue> RetryParameter {
44      get { return (IValueParameter<IntValue>)Parameters["Retry"]; }
45    }
[3872]46
47    private IEvaluationChannel Channel {
48      get { return ChannelParameter.Value; }
49    }
[6470]50    #endregion
[3872]51
[4722]52
[6470]53    #region Construction & Cloning
[4722]54    [StorableConstructor]
55    protected EvaluationServiceClient(bool deserializing) : base(deserializing) { }
[6519]56    protected EvaluationServiceClient(EvaluationServiceClient original, Cloner cloner)
57      : base(original, cloner) {
[6470]58      RegisterEvents();
[6519]59    }
[3872]60    public EvaluationServiceClient()
61      : base() {
62      Parameters.Add(new ValueParameter<IEvaluationChannel>("Channel", "The channel over which to call the remote function."));
[3895]63      Parameters.Add(new ValueParameter<IntValue>("Retry", "How many times the client should retry obtaining a quality in case there is an exception. Note that it immediately aborts when the channel cannot be opened.", new IntValue(10)));
[6470]64      RegisterEvents();
[3872]65    }
[6470]66    public override IDeepCloneable Clone(Cloner cloner) {
67      return new EvaluationServiceClient(this, cloner);
68    }
69    [StorableHook(HookType.AfterDeserialization)]
70    private void AfterDeserialization() {
71      ChannelParameter_ValueChanged(this, EventArgs.Empty);
72      RegisterEvents();
73    }
74    #endregion
[3872]75
76    #region IEvaluationServiceClient Members
[8298]77    public QualityMessage Evaluate(SolutionMessage solution, ExtensionRegistry qualityExtensions) {
[3895]78      int tries = 0, maxTries = RetryParameter.Value.Value;
79      bool success = false;
80      QualityMessage result = null;
81      while (!success) {
82        try {
83          tries++;
84          CheckAndOpenChannel();
85          Channel.Send(solution);
[8298]86          result = (QualityMessage)Channel.Receive(QualityMessage.CreateBuilder(), qualityExtensions);
[3895]87          success = true;
[6519]88        } catch (InvalidOperationException) {
[3895]89          throw;
[6519]90        } catch {
[3895]91          if (tries >= maxTries)
92            throw;
93        }
94      }
[8298]95      if (result != null && result.SolutionId != solution.SolutionId) throw new InvalidDataException(Name + ": Received a quality for a different solution.");
[3895]96      return result;
[3872]97    }
98
[8298]99    public void EvaluateAsync(SolutionMessage solution, ExtensionRegistry qualityExtensions, Action<QualityMessage> callback) {
[3895]100      int tries = 0, maxTries = RetryParameter.Value.Value;
101      bool success = false;
102      while (!success) {
103        try {
104          tries++;
105          CheckAndOpenChannel();
106          Channel.Send(solution);
107          success = true;
[6519]108        } catch (InvalidOperationException) {
[3895]109          throw;
[6519]110        } catch {
[3895]111          if (tries >= maxTries)
112            throw;
113        }
114      }
[8298]115      System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(ReceiveAsync), new ReceiveAsyncInfo(solution, callback, qualityExtensions));
[3872]116    }
117    #endregion
118
[6470]119    #region Auxiliary Methods
[3872]120    private void CheckAndOpenChannel() {
121      if (Channel == null) throw new InvalidOperationException(Name + ": The channel is not defined.");
122      if (!Channel.IsInitialized) {
123        try {
124          Channel.Open();
[6519]125        } catch (Exception e) {
[3872]126          throw new InvalidOperationException(Name + ": The channel could not be opened.", e);
127        }
128      }
129    }
130
[8298]131    private void ReceiveAsync(object callbackInfo) {
132      var info = (ReceiveAsyncInfo)callbackInfo;
[3895]133      QualityMessage message = null;
134      try {
[8298]135        message = (QualityMessage)Channel.Receive(QualityMessage.CreateBuilder(), info.QualityExtensions);
[6519]136      } catch { }
[8298]137      if (message != null && message.SolutionId != info.SolutionMessage.SolutionId) throw new InvalidDataException(Name + ": Received a quality for a different solution.");
138      info.CallbackDelegate.Invoke(message);
[3872]139    }
[6470]140
141    private void RegisterEvents() {
142      ChannelParameter.ValueChanged += new EventHandler(ChannelParameter_ValueChanged);
143    }
144
145    void ChannelParameter_ValueChanged(object sender, EventArgs e) {
146      if (ChannelParameter.Value == null)
147        name = "Empty EvaluationServiceClient";
148      else
149        name = String.Format("{0} ServiceClient", ChannelParameter.Value.Name);
150      OnNameChanged();
151    }
152    #endregion
[8298]153
154    private class ReceiveAsyncInfo {
155      public SolutionMessage SolutionMessage { get; set; }
156      public Action<QualityMessage> CallbackDelegate { get; set; }
157      public ExtensionRegistry QualityExtensions { get; set; }
158      public ReceiveAsyncInfo(SolutionMessage solutionMessage, Action<QualityMessage> callbackDelegate, ExtensionRegistry qualityExtensions) {
159        SolutionMessage = solutionMessage;
160        CallbackDelegate = callbackDelegate;
161        QualityExtensions = qualityExtensions;
162      }
163    }
[3872]164  }
165}
Note: See TracBrowser for help on using the repository browser.