Multithreaded Threadsafe Conversions - Crowdsourcing knowledge

Hypothetically, say you have an indefinitely deeply nested object model to convert to Speckle :blue_square::smiling_face_with_three_hearts:. And, say, that conversion sometimes completes in a time that is enough to not only make coffee :coffee: but also bake bread :baguette_bread:. :baby:=> :older_woman: Is there any advantage to moving to a multithreaded approach (specifically c#)?

There is no sequential magic in converting nested things :evergreen_tree: :evergreen_tree:to nested converted things :deciduous_tree: :deciduous_tree: just hierarchical integrity.

Have any of the specklesharp converters used Concurrent collections or other thread-safe collections to speed up conversions?

Is there any advantage to pursuing this thought? Or will I burn off all my fingers? :ambulance:

NB I’m humbly talking from a quite naive position as I’ve only ever used off thread workers in .NET for UI related tasks before and not to tree-walk nested objects and got headaches from it even then.

2 Likes

This is an interesting discussion, because there could be quite a significant performance bump if you could utilise parallel computation.

To my knowledge, none of our connectors directly use multithreading for ToSpeckle conversion. At least not for the recursive ConvertToSpeckle operation which I think is what you are talking about.

How easy this would be to get working very much depends on what application you are interfacing with.
It’s common for application APIs to have limitations about what you can do from outside the main thread.

For Revit for example, you basically can’t do anything from outside the main thread. So this would stop you performing any conversion multi-threaded.

Other applications might only have this limitation for creating/editing geometry, ToNative conversion would be limited to single threaded, but not necessarily ToSpeckle. So it might be possible to create ToSpeckle conversion that can be run in parallel.


That being said, there might be quicker/easier fixes for poor performance. Without knowing what application you are hypothetically talking about, this may or may not be a useful suggestion. But normally, when you are running into performance issues, you want to use a profiler to identify parts of your code that are particularly slow. You can then work on optimising those parts.

In general, I would highly recommend profiling your code before attempting to implement any sort of performance optimisation. There is a good chance that conversion takes up a much smaller % of time than you think it does, and that other things are bogging it down.

1 Like

Hey @jonathon!

Just to add on @Jedd’s answer. The only place we are using Tasks to concurrently convert objects is in Grasshopper.

But that’s implemented using the GH_TaskCapableConverter, and works on a “flat list” of object, attempting conversion of each item individually. Not sure how well this will generalise to nested recursive conversions, as most of the complexity is taken care of by the Grasshopper class implementation.

1 Like

This may hypothetically be about Navisworks which is a bottomless pit of nested objects. The upside is that none of these can be self or self-parental relationships.

The API kernel is VERY different between Navisworks and Revit with regard to the main thread. The main problem with Navisworks is that it is very fragile with its memory protection and processes just up-and-leave - in part as the core API is still the same COM interface I was using ~12 years ago. I have been thinking about moving conversion tasks off the thread (if possible) simply to avoid some of that touchiness - perhaps I’ll just try it and feedback.

2 Likes

The connector is an important influence to how the multi-threading could work with conversions. Something I really like from the speckle 1.0 unity connector was how it broke down the conversion process into specific unity steps (i.e. hierarchy setup, component creation, component data processing) which made it helpful for isolating heavy tasks and ended up building nice que of objects that could be fed into the converter… It also would setup a que of commands that needed to be done on the main thread (Unity doesn’t play nice with the typical Task and async/await since it has a playerloop thread). Not sure if any of this helps, seems like Navisworks is a bit sensitive :crying_cat_face:

2 Likes

Small update.
I’m tentatively discovering which API calls can be made multithreaded and which cannot. Therefore good news I am seeing incremental improvements between much crashing and burning.

It seems some properties of some parts of the internal object store retain links to the main thread even if deep cloned. Touch them and :fire: :fire_engine:

No magic bullet yet, big models take a while to convert. What is satisfying though, small selections are now whizzy which for the use-case of recording issues quickly is ideal.

Screenshot 2022-06-14 at 13.24.35
Yellow logs appear near-simultaneously

3 Likes

I haven’t worked the Navisworks API, but in terms of touchiness if it’s similar to Revit API, to my experience, it’s not easy to find those multithread-able objects. Mainly because you don’t have any control on when a thread might want to access an object. You might be lucky and change an object from another thread with no issues, but in some other random time it might throw an exception.

2 Likes