Python Loop Speed Performance Question & C++ MPxCommand Question

98 views
Skip to first unread message

daeseok chae

unread,
Sep 23, 2022, 2:20:57 AM9/23/22
to Python Programming for Autodesk Maya
Hello,

I am writing a script that extracts a Point located in a mesh using anyIntersection of MFnMesh.

However, there are too many points, so the performance does not come out while looping.

So I'm trying to find another way, but it's not easy to find example code.
Here's the method I've tried:

1. I tried to work the Python Loop part with C++ MPxCommand, but I couldn't find a way to return data by executing the Arguments in the form of Float3Array (Point Positions) and the corresponding command. (Return : IntArray)
2. It is said that the part can be written in C++ using PyBind, but I know that the For Loop speed is limited due to the same GIL issue. Is there any way to solve it??
3. It seems that there is no way to increase the speed of the current Python Loop by raising the speed of the loop as much as possible.

Loop Count : 1,000,0000 Under
anyIntersection: 4 Direction (Up, Left, Right, Down)

thank you

Marcus Ottosson

unread,
Sep 23, 2022, 2:50:03 AM9/23/22
to python_in...@googlegroups.com

Hello! I can shed some light on these.

I tried to work the Python Loop part with C++ MPxCommand, but I couldn’t find a way to return data by executing the Arguments in the form of Float3Array (Point Positions) and the corresponding command. (Return : IntArray)

If you are certain that looping isn’t going to be fast enough in Python, which I don't doubt, then yes this is what I would do. You won’t be able to return data outside of simple types like integers, floats and strings. But what you can do is serialise the data into e.g. JSON and output a string, and then deserialise it from Python. This is what I normally do. At a certain point, deserialising can become a bottleneck, at which point you have a JSON deserialiser in PySide2 which may be faster.

It is said that the part can be written in C++ using PyBind, but I know that the For Loop speed is limited due to the same GIL issue. Is there any way to solve it??

This point was what prompted me to reply - don’t do it! :D

Both MPxCommand and PyBind can work outside of any GIL - they are both called outside of Python - and while PyBind can return more complex types like vectors and even Python objects it is terribly inconvenient to work with in Maya. Because Maya - and Python in general - cannot reload or unload a binary Python module. Yes, you read that right. Once you import myBinaryModule you cannot unload it. At all. The only recourse is restarting Maya.

Other than that, if that isn’t a problem, then PyBind is a good option for this. You can even pass a NumPy data structure, which would bypass Python even further and keep all data - especially heavy data - in C++ and be as fast as it can be.

It seems that there is no way to increase the speed of the current Python Loop by raising the speed of the loop as much as possible.

Hard to say without having an example. Loops in Python shouldn’t be a bottleneck in general; but it’s possible the repeated access to a Maya API class could. Are you able to share a small reproducible? Would be curious to see what the problem may be.

Best,
Marcus


--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/cc20157f-7440-454a-a230-e5cd1d84e47en%40googlegroups.com.

daeseok chae

unread,
Sep 23, 2022, 3:05:21 AM9/23/22
to Python Programming for Autodesk Maya
Hello, thanks for the reply.

I'll show you a simple example of the Python code I'm currently writing.

```
from maya.api import OpenMaya

DIRECTION_VEC = [OpenMaya.MFloatVector(0, 1, 0), OpenMaya.MFloatVector(0, -1, 0), OpenMaya.MFloatVector(1, 0, 0), OpenMaya.MFloatVector(-1, 0, 0)]
mesh = "pCube1" # Deformed
selectionList = OpenMaya.MGlobal.getSelectionListByName(mesh)
mDagPath = selectionList.getDagPath(0)
meshFn = OpenMaya.MFnMesh(mDagPath)

def isIntersectPoints(meshFn, point):
    sourcePt = OpenMaya.MFloatPoint(list(point))
        for directionVec in DIRECTION_VEC:
            if not meshFn.anyIntersection(sourcePt, directionVec, OpenMaya.MSpace.kWorld, 9999, False):
                return False;
    return True

idsList = []
index = 0
for point in positions: # positions e.g) [(0, 0, 0), (0.5, 0.5, 0.5) ... ] count : 10,000
    if isIntersectPoints(meshFn, point):
        idsList.append(index)
    index += 1
```

Thank you.
2022년 9월 23일 금요일 오후 3시 50분 3초 UTC+9에 Marcus Ottosson님이 작성:

Marcus Ottosson

unread,
Sep 23, 2022, 3:07:53 AM9/23/22
to python_in...@googlegroups.com

Thanks, the first potential optimisation I can spot is the use of Maya API 1.0. I would take 2.0 for a spin also - i.e. from maya.api import OpenMaya - I would expect either a small or major improvement, since there is less serialisation going on between Python and C++ in 2.0.


daeseok chae

unread,
Sep 23, 2022, 3:17:07 AM9/23/22
to Python Programming for Autodesk Maya
hello
I'm already using from maya.api import OpenMaya.
So should I use from maya import OpenMaya?
Is it 1.0 > 2.0?

2022년 9월 23일 금요일 오후 4시 7분 53초 UTC+9에 Marcus Ottosson님이 작성:

Marcus Ottosson

unread,
Sep 23, 2022, 3:18:35 AM9/23/22
to Python Programming for Autodesk Maya
Oh, yes you are. My mistake, I'll need to adjust my glasses before replying. 😅

daeseok chae

unread,
Sep 23, 2022, 3:27:38 AM9/23/22
to Python Programming for Autodesk Maya
Thank you.

I think it will be difficult at the Python level, so I am trying to implement the code in C++.

Let's try Array Argument & Return using JSON to String.

2022년 9월 23일 금요일 오후 4시 18분 35초 UTC+9에 Marcus Ottosson님이 작성:

Justin Israel

unread,
Sep 23, 2022, 3:20:05 PM9/23/22
to python_in...@googlegroups.com
I just want to point out that it's not clear that the python GIL is going to be an issue here unless you are trying to multithread this operation (which your code doesn't show). The GIL prevents python code from running in parallel. It can run concurrently by context switching back and forth quickly to appear parallel. But again, your example code shows that it's just a single thread doing loops.
So really I think you are seeing the performance issue from having a super large outer loop * inner loop, and how python has to do alot more work when it comes to performing reflection on each type, as well as a temporary list conversion on each point tuple. This is where you might see your gains from C++ doing the loops, by being able to static type the variables. 


Reply all
Reply to author
Forward
0 new messages