<div dir="ltr">Ok right. There are some details which need to modify the idea:<div>- Thread safety:</div><div>Instead of locking the thread id could be saved in the object and then checked when the object is used. If the thread id is wrong then a new object must be created.</div><div>I think there is no additional locking necessary because of the GIL.</div><div><br></div><div>- Startup time and memory waste:</div><div>This idea can be improved if lazy object initalization is used. So that the tuples and dicts are only created when the function is called the first time and then these objects are kept in memory as long as the module is not unloaded.</div><div>This would not hurt the startup time and save memory.</div><div>One more detail which needs to be handled is recursive calling of the function. This can be easily handled by the reference counter. To keep the implementation simple and to not get too memory hungry this optimization should support just the first call level and not iterative calls.</div><div><br></div><div>Regards,</div><div><br></div><div>Martin</div><div><br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">Am Sa., 9. März 2019 um 03:23 Uhr schrieb Steven D'Aprano <<a href="mailto:steve@pearwood.info">steve@pearwood.info</a>>:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">On Fri, Mar 08, 2019 at 10:16:02PM +0100, Martin Bammer wrote:<br>
> Hi,<br>
> <br>
> what about the idea that the interpreter preallocates and <br>
> preinitializes the tuples and dicts for function calls where possible <br>
> when loading a module?<br>
<br>
That's an implementation detail. CPython may or may not use tuples and <br>
dicts to call functions, but I don't think that's specified by the <br>
language. So we're talking about a potential optimization of one <br>
interpreter, not a language change.<br>
<br>
If the idea survives cursory discussion here, the Python-Dev mailing <br>
list is probably a better place to discuss it further.<br>
<br>
<br>
> Before calling a function then the interpreter would just need to update<br>
> the items which are dynamic and then call the function.<br>
<br>
As Greg points out, that would be unsafe when using threads. Let's say <br>
you have two threads, A and B, and both call function spam(). A wants to <br>
call spam(1, 2) and B wants to call spam(3, 4). Because of the <br>
unpredictable order that threaded code runs, we might have:<br>
<br>
    A sets the argument tuple to (1, 2)<br>
    B sets the argument tuple to (2, 3)<br>
    B calls spam()<br>
    A calls spam() # Oops!<br>
<br>
and mysterious, difficult to reproduce errors occur.<br>
<br>
It may be possible to solve this with locks, but that would probably <br>
slow code down horribly.<br>
<br>
[...]<br>
> Without the optimization the interpreter would need to:<br>
> <br>
> - create new tuple (allocate memory)<br>
> - write constant into first tuple index.<br>
> - create dict (allocate memory)<br>
> - add key+value<br>
> - add key+value<br>
> - call function<br>
<br>
Sure, and that happens at runtime, just before the function is called. <br>
But the same series of allocations would have to occur under your idea <br>
too, it would just happen when the module loads. And then the pre- <br>
allocated tuples and dicts would hang around forever, wasting memory. <br>
Even if it turns out that the function never actually gets called:<br>
<br>
    for x in sequence:<br>
        if condition(x):  # always returns False!<br>
            function(...)<br>
<br>
the compiler will have pre-allocated the memory to call it.<br>
<br>
So I suspect this is going to be very memory hungry. Trading off memory <br>
for speed might be worthwhile, but it is a trade-off that will make <br>
certain things worse rather than better.<br>
<br>
<br>
> If this idea is possible to implement I assume the function calls would<br>
> receive a great speed improvment.<br>
<br>
Well, it might decrease the overhead of calling a function, but that's <br>
usually only a small proportion of the total time to make function <br>
calls. So it might not help as much as you expect, except in the case <br>
where you have lots and lots of function calls each of which do only a <br>
tiny amount of work.<br>
<br>
But that has to be balanced against the slowdown that occurs when the <br>
module loads, when the same memory allocations (but not deallocations) <br>
would occur. Starting up Python is already pretty slow compared to other <br>
languages, this would probably make it worse.<br>
<br>
Even if it became a nett win for some applications, for others it would <br>
likely be a nett loss. My guess is that it would probably hurt the cases <br>
which are already uncomfortably slow, while benefitting the cases that <br>
don't need much optimization.<br>
<br>
But that's just a guess, and not an especially educated guess at that.<br>
<br>
<br>
-- <br>
Steven<br>
_______________________________________________<br>
Python-ideas mailing list<br>
<a href="mailto:Python-ideas@python.org" target="_blank">Python-ideas@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/python-ideas" rel="noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/python-ideas</a><br>
Code of Conduct: <a href="http://python.org/psf/codeofconduct/" rel="noreferrer" target="_blank">http://python.org/psf/codeofconduct/</a><br>
</blockquote></div>