On 2024-07-17 10:30 a.m., Sven Bardos via python-win32 wrote:
Hi Mark,
I found some time to debug and profile my issue a little bit more.
In my scenario I call a COM method which returns a list of 14195
integers plus the amount of the found objects.
If I profile that call I get the following:
ncalls tottime percall cumtime percall filename:lineno(function)
...
1 0.000 0.000 0.025 0.025 __init__.py:572(_ApplyTypes_)
1 0.000 0.000 0.007 0.007 __init__.py:603(_get_good_object_)
14195 0.001 0.000 0.001 0.000
__init__.py:608(_get_good_single_object_)
14198/1 0.005 0.000 0.007 0.007
__init__.py:614(_get_good_object_)
...
So _get_good_object_ is called ~14200 times.
If I do that in a loop 100x, I get an execution time of ~3.3s
If I change the code in the _ApplyTypes_ function to:
def _ApplyTypes_(self, dispid, wFlags, retType, argTypes, user,
resultCLSID, *args):
return self._oleobj_.InvokeTypes(dispid, 0, wFlags, retType, argTypes,
*args)
# return self._get_good_object_(
# self._oleobj_.InvokeTypes(dispid, 0, wFlags, retType, argTypes,
*args),
# user,
# resultCLSID,
# )
that is, avoiding the _get_good_object_() calls, the execution time is
~1.6s for 100 iterations. Which is ~50% of the original time. The
result is the same, in this case.
I'm certainly up for looking at optimizations to how this works, but I
don't think it's as simple as not calling the function - there are cases
where it would return different objects. I don't think an instance
method is needed (ie, maybe we could just call the final implementation
and maybe even inline some of those calls, but if you say the result is
identical, it looks a little like there are just 2 isinstance() calls
which return False in this scenario, so maybe this might also offer
optimization ideas (eg, if the type in question for your examples are
builtin types like int/string/etc, maybe these could be checked before
making any other calls?).
HTH,
Mark
Do you have any thoughts on this?
Best regards,
Sven
Am Mi., 17. Apr. 2024 um 17:19 Uhr schrieb Mark Hammond
<skippy.hamm...@gmail.com>:
I'm mildly surprised by that - a profiler might show some
low-hanging fruit, and/or might show different characteristics
when many more functions are used. However, the primary reason for
EnsureDispatch is for better support of the object model - there's
far more context available and this less chance of upsetting some
COM objects - eg, when `foo.bar` is seen, EnsureDispatch knows for
sure that `bar` is a method, but dynamic dispatch doesn't know if
the resulting object is going to be called or not.
HTH,
Mark
On 2024-04-17 2:07 a.m., Sven Bardos via python-win32 wrote:
Hi,
shouldn't be EnsureDispatch be faster than Dispatch once the code
generation is done?
I've measured it by calling 6000 COM calls like this:
dirpath = Path('C:/Users/sbardos/AppData/Local/Temp/gen_py/3.10/')
if dirpath.exists() and dirpath.is_dir():
shutil.rmtree(dirpath)
app = Dispatch("CT.Application")
job = app.CreateJobObject()
start = timer()
for i in range(2000):
cnt, devIds = job.GetAllDeviceIds()
cnt, sheetIds = job.GetSheetIds()
dev = job.CreateDeviceObject()
end = timer()
print(f"Time ellapsed (late): {end - start}s")
and the ensure Dispatch version:
app = EnsureDispatch("CT.Application")
job = app.CreateJobObject()
start = timer()
for i in range(2000):
cnt, devIds = job.GetAllDeviceIds(None)
cnt, sheetIds = job.GetSheetIds(None)
dev = job.CreateDeviceObject()
end = timer()
print(f"Time ellapsed (early): {end - start}s")
EnsureDispatch is a little bit slower ~4.2s compared to ~4.0s.
If I don't get a performance boost with EnsureDispatch, is there
even a point using it?
Thanks,
Sven
_______________________________________________
python-win32 mailing list
python-win32@python.org
https://mail.python.org/mailman/listinfo/python-win32
_______________________________________________
python-win32 mailing list
python-win32@python.org
https://mail.python.org/mailman/listinfo/python-win32
_______________________________________________
python-win32 mailing list
python-win32@python.org
https://mail.python.org/mailman/listinfo/python-win32