Using TPL for parallel computing and RhinoCommon C# dot net

I have hundreds of brepbrep intersection, sweep function etc, which are making the tool quite slow.
So I want to use Task parallel library.
I had never used it before.
Would be nice to see a small source code, so would be easier for me to catch it.
It would help me to start with TPL with RhinoCommon c# dot net.

In certain cases parallel processing can be used, but Rhino is not thread-safe. I have encountered weird, unrepeatable crashes when doing stuff in parallel with TPL. Having said that, please see the example below.

Typically, if you have brep-brep intersection in a for loop like this:

Brep cutter;
Brep[] targets;
double tolerance = doc.ModelAbsoluteTolerance;

List<Curve> allCurves = new List<Curve>();
Point3dList allPoints = new Point3dList();
for (int i =0; i < targets.Length; ++i)
{
    Curve[] intersections;
    Point3d[] points;
    if (Intersection.BrepBrep(cutter, targets[i], tolerance, out intersections, out points))
    {
        if (null != intersections)
            allCurves.AddRange(intersections);
        if (null != points)
            allPoints.AddRange(points);
    }
}

you can make a TPL version like so

Brep cutter;
Brep[] targets;
double tolerance = doc.ModelAbsoluteTolerance;

ConcurrrentBag<Curve> allCurves = new ConcurrrentBag<Curve>();
ConcurrrentBag<Point3d> allPoints = new ConcurrrentBag<Point3d>();
Parallel.For (0, targets.Length, i => 
{
    Curve[] intersections;
    Point3d[] points;
    if (Intersection.BrepBrep(cutter, targets[i], tolerance, out intersections, out points))
    {
        if (null != intersections)
            foreach(var crv in intersections)
                allCurves.Add(crv);

        if (null != points)
            foreach(var pt in points)
                allPoints.Add(pt);
    }
});

The same goes for foreach loops, that get turned into Parallel.ForEach.

Because multiple threads access the allCurves and allPoints collections, you should use a thread-safe collection, like ConcurentBag<T>. It is good to realize that these collections are accessed by multiple threads, whereas the intersections and points arrays are local to each thread.

1 Like

Thank you so much ! It is a big help. I was not understanding how to use it at all. I had no clue.
I need to be prepared for un-expected crashes. At list I can see one example now and try it by trial and error now.

Many thanks !
:smile:

We have been experiencing crashes when trying to use Brep.CreatePlanarBreps in multiple threads simultaneously, so I would avoid that one.

Do you have a sample that causes a crash? We are always trying to make our geometry functions thread safe, but of course bugs do exist.

Here is the issue I submitted to Github in May: https://github.com/mcneel/rhinocommon/issues/167

Ah yes, the github bugtracker. We keep intending to move all of those issues from github to youtrack and close the one on github.

I’ve moved this report to youtrack at
http://mcneel.myjetbrains.com/youtrack/issue/RH-31012
Thanks!

I want to add curves as Rhino doc object from ConcurrrentBag allCurves.
How to write it ?

Can I draw all the curves at once in Rhino doc ?

No, you should just do this, outside of a parallel loop:

foreach(var crv in allCurves)
    doc.Objects.AddCurve(crv);
1 Like

@menno is correct. Any time you are adding items to or removing items from a list you should be doing this on a single thread. Only specialized collections like ConcurrentBag let you add items in a thread-safe way.

1 Like

Many thanks menno !

It is working ! Thanks.
speed looks almost same for drawing ConcurrrentBag Verses List