Conversation
There's not much to change in Do you have benchmarks on the memory usage improvement? If all we're saving is a few bytes while being 160% slower, then I would be -1 on this. |
I do not understand the question. The issue is that this operation never (!) frees up memory. You can fill the list with 1_000 elements (+8 KB), or with 1_000_000 elements (+8 MB), and no |
|
Let me put it another way: if you think this is not worth changing, then why does the list shrink at all during other operations that remove items? Why do not we just remove the shrinking altogether, and thus speed up all similar methods (for example, |
|
A question but:
Who is the "you"? |
|
Deleting an item from a list is common. Deleting many items at once using
I meant by running our test suite or something like that, or just by running your microbenchmark. |
A potential reader who is able to contribute to the repository. Excuse me if the tone of this sentence seems out of place (actually, I was just trying to point out the logic; though, there are already so many of my stalled issues in python/cpython that perhaps I am wasting my time on this…). I had my doubts about it too; editing it a couple of hours after posting seems wrong to me.
It is not necessary to remove many items at once. Surely there is someone who uses
Again, I do not understand what you want me to measure. In the current implementation, the list capacity does not decrease when deleting by index. Why measure logic that is already clearly demonstrated in the issue using |
|
Btw, we do bypass the reallocation in list_resize() sometimes: Depending on the allocated value, you might be hitting different paths. I wonder if your empty case is some magical threshold (it wouldbe good to know what happens with lists of various sizes as all your tests are only for lists of size 0 or 1, and I don't know if this happy path is taken or not and which path is actually taken). I also believe that the What's the effect of that on non-free threaded builds (or on FT builds, I don't know which one you used). So the call to
After your PR, is the |
Hm? They wouldn't need to free things up. If you're frequently deleting and appending, then not resizing on delete is the more performant option. Generally speaking, I'm more for speed efficiency than for memory efficiency (Python users rarely care about saving a little memory, and those who do will be using the |
The first case:
The second case:
I was wrong about the second case, since it actually reallocates the array (after the PR), but to the exact same capacity (perhaps an oversight in the implementation?). See
I agree, but I am not sure how to do that with pyperf. So I literally did exactly what you asked for in #158592 (comment).
In theory, its performance will be close to that of Oh, yes, I used a non-free-threaded build. If it had been otherwise, I would have mentioned it. But since the issue is not bound to free threading, I assumed it was obvious.
Yes. |
The peak size is not the same as the average size, I should note. From a memory perspective, not freeing up memory is much worse, especially if there are many lists.
I disagree. Lists of arbitrary objects are not what NumPy is about. |
For 3-4 items:
(Before: 19.3, so +2.1 ns) |
To be clear, you can simply compare Well, it seems a bit off that we are having a discussion here about whether the fix is actually needed, which essentially continues the discussion from the issue. This does not really feel like a review, but… oh well. If we imagine that we are from the Ministry of Silly Walks… (just a joke, in support of how I myself was mistaken about the behavior of |
|
We're just being cautious; "2.61x slower" sets off alarm bells for a maintainer. |
Fixes the linked issue with a simple one-line change, copy-pasted from
list_pop_impl(). Ideally, thev == NULLbranch of thelist_ass_item_lock_held()function should be code-synchronized with the one mentioned, since the implementation oflist_pop_impl()appears to be more efficient, but that is beyond the scope of this PR.Performance comparison:
Details
The first case always reallocates the array,
while the second case never reallocates the array(see #158602 (comment)). The results appear to be a performance regression, but it is important to understand what this change actually does. Namely, it simply restores the missed reallocation that other methods already perform (del list[slice],list.pop(),list.remove(), etc.)! If you are concerned about this, you should change thelist_resize()implementation rather than making the collection non-shrinkable in terms of capacity.I decided not to add a regression test because it would depend on the exact behavior of the
list_resize()function (specifically, when it decides to change the capacity), which would require updating the test whenever its condition changed.del list[index]never reallocates the array #158592