Tasked componet generates different (inconsistent) results


This is my first post to the forum so might sound a bit not so professional in regards programming terms and concepts.
I’m developing a system for managing real tree branches and one of the components has to split a mesh in parts. It creates a bounding box of the branch, a dozen of surfaces along a line and then after converting the surfaces to meshes I use the Mesh.Split() command. The thing is I made this component multi-threaded and when using tasks as by the official example on the Mcneel site the results are always different and less accurate than the single threaded solution. The code I use is the same for both. Anyone has and idea as to why this is happening? Also it is not very clear what is happening when all threads finish? When is the final data assigned to the output parameters? It seems as if the next components do not get all data and recomputing the solutions sometimes fixes the problem. Is there something code wise I should be doing? Expiring does not work.

Tasked run #1:

Tasked run #2:

Single thread - shows normal behaviour:

Hi @ankere

  • Did you try this in Rhino WIP?

MeshSplit is completely rewritten there, and the version for Rhino 5/6 will not get major updates in normal Service Releases.



Giulio Piacentino
for Robert McNeel & Associates

Thanks for the reply Giulio,
Unfortunately, I’m part of an academic environment and using beta software is not the best solution to achieve results. I will consult with my supervisors if I can use WIP version on the lab computers.

Nevertheless I also confirmed while debugging that results are sent to the output parameters before all threads finish. Is there an elegant way to tell the component to wait for all results before they are sent further?

Then, there might also be some problem in the implementation. As I am not super-informed on Grasshopper parallelized components, so I’m forwarding this request to @stevebaer and @DavidRutten.

I also remember that we discussed Mesh.Split a few months ago. We realized that the old non-WIP implementation of Mesh.Split was not guaranteed to be thread safe.

Please let me know when/if you have updates on Rhino WIP.



Giulio Piacentino
for Robert McNeel & Associates

How did you confirm this? I wouldn’t expect this to happen and am trying to get a better understanding of what you are seeing

Hello Steve,
The next components get lists with less elements than expected(or than the normal single thread) and throw exceptions. Recomputing does help but not always. It seems the exception comes from the SetData()? or I might be totally wrong. Here are two pictures:

This is the error run that says NullReference although there is data in Centrelines in all cases as I have taken care of the constructor of class handling the results.

public class SolveResults
    public SolveResults()
        Centrelines = new List<Polyline>();
        Edges = new List<List<Polyline>>();
        Errors = new List<string>();
    public List<Polyline> Centrelines { get; set; }
    public List<List<Polyline>> Edges { get; set; }
    public List<string> Errors { get; set; }
    public BoundingBox BBox { get; set; }

Next is the run before the exception and as can be seen the data in each polyline is around 10-18 points as it should be.

Here is also a trace if it can help:

Message=Object reference not set to an instance of an object.
 at Grasshopper.Kernel.Types.GH_Curve..ctor(Curve curve)
 at Grasshopper.Kernel.GH_Convert.ToGeometricGoo(Object data)
 at Grasshopper.Kernel.Parameters.Param_Geometry.PreferredCast(Object data)
 at Grasshopper.Kernel.GH_Param`1.Cast_Object(Object data)
 at Grasshopper.Kernel.GH_Param`1.AddVolatileDataList(GH_Path path, IEnumerable list)
 at Grasshopper.Kernel.GH_Component.GH_StructureIterator.SetDataList(Int32 index, IEnumerable list, Int32 itemIndexOverride)
 at MakeCentreLines.MakeCentreLinesComponent.SolveInstance(IGH_DataAccess DA) in...\MakeCentreLines\MakeCentreLinesComponent.cs:line 147
 at Grasshopper.Kernel.GH_Component.Solution_Compute_MixedAccess(GH_StructureIterator it)

Did you have a chance to try this in V7? I would be good to know if you get different results

I tried today and at first glance it appears to be working but then in the next components it does not behave as expected. This code for one piece of the mesh would never return null (usually at k=0?) as naked edges in V6 but now it does several times:

 int dmc = mp.DisjointMeshCount;
 Mesh[] mpPieces = mp.SplitDisjointPieces();

     for (int k = 0; k < dmc; k++)
         Polyline[] naked = mpPieces[k].GetNakedEdges();

If this does not work my algorithm fails (even if I skip the null edges). It also seems the branch type detection that also uses naked edges fails. Result from run:

Do you think it is possible to make something to ensure the split is thread safe in Rhino 6? Is there any chance of getting that function to be thread safe in future service release?

I was thinking about locking the split but then the result is just as bit faster than the single thread:

Mesh[] meshParts = M.Split(cut_planes);

Or maybe I should define my own split function? Is there some reference or code I can check for that?

1 Like

I think there’s no point to make things multithreaded if there’s a megalock. It all resorts to single thread anyways. There’s no plan to make major improvements to mesh split in Rhino 6 at this point.

Thank you Giulio,

I understand that you will not make any changes to v6 but as there is not clear release date on 7 and I cannot use betas I really need to make this work fast with version 6 for now. I’m planning on splitting hundreds of elements and even if I we have Ryzen 9 and Nvidia 2080Ti at lab its not fast enough when I use only one core and my GPU is Idle.

Any further suggestions are welcome.

For V6, I don’t know how to help. Try V7. I am unaware of other things I can do, also.

Thank you for your work Giulio,
I think I was a bit too emotional at that time. Its a tough time.

1 Like