/// <summary> /// Explicitly clear the list (which isn't technically required, since the removal of /// our object will cause the GCC (the .NET garbage collector) to remove it). /// The GCC has overhead, so in a real application you may wish to re-use these data /// objects instead of destroying them. /// </summary> /// <param name="dss"></param> /// <param name="data"></param> private void ReleaseMemory(DataShareSingleton dss, MyEntityData data) { data.DummyList.Clear(); Object obj = null; if (!dss.RuntimeInfoDict.TryRemove(data.Key, out obj)) { // perhaps log error?... it is up to you string xx = ""; } }
// Synchronous case for comparison private void SendDataSync(DataShareSingleton dss, MyEntityData myData) { int nn = 0; foreach (DummyDataClass ddc in myData.DummyList) { if ((nn % 700) == 0) { System.Threading.Thread.Sleep(10); } nn++; } ReleaseMemory(dss, myData); }
/// <summary> /// Note: Use this if you want to emulate communicating with external devices. /// Emulates a very long-running send operation, followed by a memory release. /// Note that we don't care about the status of the 'send', but if we /// did, it should likely be logged (since the model has 'moved on' anyway). /// </summary> /// <param name="myData">Entity's data</param> /// <returns></returns> private async Task SendData(DataShareSingleton dss, MyEntityData myData) { await Task.Run(() => { int nn = 0; foreach (DummyDataClass ddc in myData.DummyList) { if ((nn % 700) == 0) { System.Threading.Thread.Sleep(10); } nn++; } ReleaseMemory(dss, myData); }); }
/// <summary> /// Method called when a process token executes the step. /// </summary> public ExitType Execute(IStepExecutionContext context) { // Examine what our AssociatedObject is var simioEntity = context.AssociatedObject; string name = simioEntity.HierarchicalDisplayName; var info = context.ExecutionInformation; string runInfo = $"Model={info.ModelName} Experiment={info.ExperimentName} Scenario={info.ScenarioName} Rep#={info.ReplicationNumber}"; string uniqueKey = $"{info.ModelName}:{info.ExperimentName}:{info.ScenarioName}:{info.ReplicationNumber}"; // Example of how to get the value of a step property, in this case where the Step is located, // which is set by the human when the step is placed. IPropertyReader myExpressionProp = _properties.GetProperty("StepLocation") as IPropertyReader; string myLocation = myExpressionProp.GetStringValue(context); if (name.StartsWith("DefaultEntity.")) { string[] tokens = name.Split('.'); DataShareSingleton dss = DataShareSingleton.Instance; string key = name; MyEntityData entityData = null; // Fetch or create our entity data that will accompany the entity. // This data is stored in a dictionary within singleton object. // and fetched by its key (the entity name) object obj = null; if (!dss.RuntimeInfoDict.TryGetValue(key, out obj)) { entityData = new MyEntityData(key); dss.RuntimeInfoDict.TryAdd(key, entityData); } else { entityData = obj as MyEntityData; } var whereAmI = myLocation; entityData.TheStepsIHaveSeen.Add(whereAmI); entityData.LastLocationTime = DateTimeOffset.Now; // We're only going to do processing for two locations here, but you // can see that any of the identified steps can do processing. switch (myLocation) { case "OnCreated": // Create our data structures { // A one-time build of data if (entityData.DummyList.Count == 0) { entityData.DummyList = new List <DummyDataClass>(); // Let's store a bunch of objects for this entity for (int kk = 0; kk < 100000; kk++) { DummyDataClass ddc = new DummyDataClass(kk, (double)kk * kk); entityData.DummyList.Add(ddc); } } }; break; case "OnVisiting": { } break; case "OnDestroying": { TimeSpan delta = DateTimeOffset.Now.Subtract(entityData.CreationTime); StringBuilder sb = new StringBuilder($" It took me {delta.TotalMilliseconds} ms to visit: "); var writeOptions = ((IStringState)simioEntity.States["WriteOptions"]).Value; foreach (string ss in entityData.TheStepsIHaveSeen) { sb.Append($"{ss} "); } // Example of how to display a trace line for the step. context.ExecutionInformation.TraceInformation($"{sb}"); // Emulate the writing of the data using a very slow protocol if (writeOptions == "Async") { Task task = SendData(dss, entityData); } else if (writeOptions == "Sync") { SendDataSync(dss, entityData); } else // If neither... don't write, but we better release our memory. { ReleaseMemory(dss, entityData); } }; break; case "Server1_BeforeProcessing": break; case "Server1_AfterProcessing": break; case "Source_OnCreating": break; default: { context.ExecutionInformation.TraceInformation($"Unhandled StepLocation={myLocation}"); }; break; } // switch } else // put logic for any unhandled associated objects. { string xx = ""; } return(ExitType.FirstExit); }