algorithmic modeling for Rhino
Hi Giulio and Steve,
I've recently noticed a couple of bottleneck with the GHPython component which can quite severely impede on performance. Thought I would bring them up here so as to hopefully help others facing similar issues.
1) Letting Grasshopper perform the "implied" loop can be substantially slower than making the loop yourself inside the Python script. This is understandable, however the strangest thing is that it is MUCH slower if the definition has been saved than when it has not (by about a factor of 10)!
2) Setting type hints seems to be slower than inputting data with "No Type Hint". This depends a bit on which type is being input, but this seems to be fairly consistent. In the attached example by about a factor of 3. I suppose this is understandable, but not exactly ideal.
3) Outputtings lists with many items will often take longer than the actual computation performed by the script. I suppose this is more of a Grasshopper thing. My workaround has been to wrap the list in a Python list and pass this along as an item, which will be ALOT faster with large lists (this was crucial to both the Tower and ShapeOP where we pass around large amounts of constraints).
4) Calling certain RhinoCommon methods appear to be randomly much more expensive than using the C# scripting component. For instance, when iterating over a mesh's vertices and calling Mesh.Vertices.GetConnectedVertices() the elapsed time sum of these calls seem to be comprised of only a few vertices which randomly change every time the script is run. The amount of vertices differ on different machines, but the pattern remain consistent.
I'm not sure if these bottlenecks are just examples of me being dumb, if so I hope you can enlighten me to the errors of my ways :)
Attached some screenshots of an unsaved/saved definition which demonstrates the described issues. Also please find the gh definition attached.
Edit: Logged this on Github here.
Update: Added point 4), new screenshot and file demonstrating this behaviour.
Yes, Andres, yes, it is because of things like garbage collection. If you take a slightly lower threshold, you can see that the same pattern arises in C#. In general, you might have noticed that now and then the Grasshopper profiler shows a larger timing for a particular component...
Thanks Giulio, that makes sense and I have indeed noticed this. I wonder though if this also explains the GHPython cases I'm experiencing where two calls out of two thousand make up about 2/3 of the total computation time, or, whether this behaviour could simply be caused by the method of the profiling (i.e. precision and/or logic). For instance in this example:
The GHPython component is displaying the behaviour I'm describing (assuming the profiling is valid). Whereas the C# component is not i.e. it's sum of expensive call is pretty much 10 times the average call time, meaning that there are no outliers like with the GHPython component. At least that's what it looks like ;)
Hi guys, I also have a problem with ghPython perfomance. In my case, when I open gh definition (see atached files), it work fast, about 5 seconds, but if I try recompute it ,even without any changes, it works slowly (10 sec), next time 12, 15, 20, 40, 1 min... I not understand why?
Could be a memory leak caused by using the ghpythonlib library (I'm not sure if this is still a thing, but I remember Stephen and Giulio talking about it recently). In my experience, you're almost always better off (in terms of performance) using RhinoCommon directly when writing your GHPython scripts. But then again, I'm pretty biased at this point having not used either rhinoscriptsyntax (for quite a while) or ghpythonlib (more or less ever). Hope that helps!
It's sad, but before opening this, I was going to bet that this was, again, a ghpythonlib problem. I would discourage anyone from using that module at this moment, unless it is just to use a method that is otherwise not present in good rhinoscriptsyntax or Rhino (RhinoCommon).
Btw, I took the liberty to rewrite the definition to have the same result, but always work no matter the size of the triangles and using just a little bit of rhinoscriptsyntax.
for Robert McNeel & Associates
Anders, Giulio, thanks so much
This way it can be done just using Rhinocommon: (Because Rhinoscript is the Rhino's Pascal... :)
I find rhinoscript an easy and beautiful module, that works great in Python. RhinoCommon is great for other reasons; of course, it depends on what you are trying to do.
Also, rhinoscript(syntax) is procedural, while RhinoCommon is more object oriented.
I was just kidding, Giulio... Obviously 'real programmers' never use Python at all:
(Source: Marcos Besteiro)
Don't be sad Giulio, I can only imagine how difficult it must be to get all this playing nice! We've got your back, always :)