Hello Everybody,
maybe @stevebaer or @AndyPayne ?
I managed to run a bunch of headless Grasshopper solutions on async Tasks so they are solved without blocking the main UI. Now I’m trying to take Hops into this (poisonous) mix to solve long running solutions on additional Threads and possibly use network machines in future.
When using the Grasshopper Document without Hops in it, I’m expiring the solution before its Task is finished. The Document is being collected by Garbage collector - and memory is being freed up.
When moving the heavy part of the same Document into a Hops Component, it seems that something keeps the Document from being put to garbage - memory isn’t freed up.
Following is my Test Command which asks for the number of tasks to run and whether tese should use the Grasshopper Document with Hops or without. By running the Command a few times I can see my memory getting blocked up successively when using the Hops solution.
Probably it’s visible that I’m not a very seasoned programmer - and especially with this async stuff I’m sure I’m making quite a few mistakes - probably this is the reason why my system’s memory keeps getting filled up.
I would be very glad if someone could point me in the right direction on how to solve this issue!
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Rhino;
using Rhino.Commands;
using Rhino.Input;
using Grasshopper.Kernel;
using GH_IO.Serialization;
namespace GrasshopperInRhino
{
public class GHInRhinoTest : Command
{
public GHInRhinoTest()
{
Instance = this;
}
public static GHInRhinoTest Instance { get; private set; }
public override string EnglishName => "GHInRhinoTest";
protected override Result RunCommand(RhinoDoc doc, RunMode mode)
{
WaitingTask();
return Result.Success;
}
static async Task WaitingTask()
{
int numberOfTasks = 2;
bool useHops = false;
RhinoGet.GetInteger("How many parallel tasks?", false, ref numberOfTasks);
RhinoGet.GetBool("Use solution with Hops?", false, "No", "Yes", ref useHops);
List<Task> tasklist = new List<Task>();
for (int i = 0; i < numberOfTasks; i++)
{
tasklist.Add(WorkerTaskAsync("Task" + i.ToString(), useHops));
System.Threading.Thread.Sleep(200);
}
await Task.WhenAll(tasklist);
}
static async Task WorkerTaskAsync(string name, bool useHops)
{
var start = DateTime.Now;
RhinoApp.WriteLine("Enter {0}", name);
string path = "GHInRhinoTest.gh";
if (useHops)
{
path = "GHInRhinoTest_Hops.gh";
}
await Task.Run(() => SolveGrasshopper(path));
RhinoApp.WriteLine("Exit {0}, Elapsed Time: {1}", name, (DateTime.Now - start).TotalMilliseconds);
}
public static void SolveGrasshopper(string grasshopperFilePath)
{
// Set GH File and get Definition
GH_Document definition = new GH_Document();
GH_Archive archive = new GH_Archive();
archive.ReadFromFile(grasshopperFilePath);
archive.ExtractObject(definition, "Definition");
// Loop trough Grasshopper objects and compute all Context Bake Components
foreach (GH_DocumentObject ghObj in definition.Objects)
{
if (ghObj is IGH_Component comp)
{
if (comp.Name == "Context Bake")
{
IGH_Param contextBakeInput = comp.Params.Input[0];
contextBakeInput.CollectData();
contextBakeInput.ComputeData();
}
}
}
definition.ExpireSolution();
}
}
}
I’m using Mass Addition of a series of 5.000.000 small floats to simulate a heavy calculation in my Grasshopper definitions.
Here are my files:
GHInRhinoTest.gh (8.0 KB)
GHInRhinoTest_Hops.gh (8.4 KB)
GHInRhinoTest_HopsContent.gh (4.8 KB)
GHInRhinoTest.cs (2.8 KB)
Thank you!