Hello,
I have a script that relies on a large dataset of boolean difference operations. Please assume there isn’t a way to avoid this (via other geometry creation/manipulation methods)
I’ve been looking for speedier Boolean operators in Grasshopper for a bit and recently stumbled upon a post where @magicteddy found a performance increase over the standard Solid Difference component by simply calling the Rhino Common equivalent inside a scripting component.
While there is a noticeable performance difference between the two components (in favor of the magicteddy/Rhino Common version) I couldn’t help but remember reading through this post and this post in the past and thinking there is an option to leverage the magicteddy version plus enable parallel computing in the case of the A input being a long list of items.
I’ve tried to take a stab at this myself but I’m stuck on understanding how to loop within a multithreading task or rather how to execute a single operation within the looping tasks.
If I have a list with inputs A as a list of 10 objects and a B list with 150 objects each, I’m assuming I commit a thread per each item in A and then operate on the corresponding B sublist within the thread task.
I can’t seem to get it to work though and currently when I enable Parallel in my component I get an “appended” list of all possible A/B boolean differences per A item instead of the culminated result of all A/B differences merged together. I’m unclear of how to properly append the final R/result list to be single objects matching the length of A.
Here’s the code and a test file:
C#:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using Rhino;
using Rhino.Geometry;
using Grasshopper;
using Grasshopper.Kernel;
using Grasshopper.Kernel.Data;
using Grasshopper.Kernel.Types;
public class Script_Instance : GH_ScriptInstance
{
int processor_count;
double tol;
private void RunScript(System.Collections.Generic.IEnumerable<Rhino.Geometry.Brep> A, System.Collections.Generic.IEnumerable<Rhino.Geometry.Brep> B, bool Parallel, out object R)
{
//Display Component Message
processor_count = System.Environment.ProcessorCount - 1;
tol = Rhino.RhinoDoc.ActiveDoc.ModelAbsoluteTolerance;
if (Parallel)
{
R = ParallelCreateBooleanDifference(A, B);
//this.Component.Message = "processor_count + " Threads Available"";
this.Component.Message = "Parallel";
}
else
{
R = Brep.CreateBooleanDifference(A, B, tol);
this.Component.Message = " ";
}
}
private object ParallelCreateBooleanDifference(IEnumerable<Rhino.Geometry.Brep> A, IEnumerable<Rhino.Geometry.Brep> B)
{
var result = new List<Rhino.Geometry.Brep>();
// Use Parallel.ForEach to run in parallel
System.Threading.Tasks.Parallel.ForEach(A, a =>
{
foreach (var b in B)
{
// Compute the difference for each pair of A and B
var diff = Brep.CreateBooleanDifference(a, b, tol);
lock (result)
{
result.AddRange(diff);
}
}
});
return result;
}
public bool Parallel;
}
Test File:
20230907_Solid_Difference_Speed_Test_01b.gh (18.3 KB)
Model Space:
Graph Space:
Speeds:
I’ve read that there is overhead in parallel computation and that it’s not always faster depending on the setup. Currently, I just want to get the logic working to even be able to compare that case in this test file.
Thank you all for your help!