-
-
Notifications
You must be signed in to change notification settings - Fork 30.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
a -= b should be fast if a is a small set and b is a large set #52672
Comments
|
Raymond, have you forgotten to attach the patch or have you just set the stage to 'patch review' by mistake? |
The problem is apparently due to the fact that small_set -= large_set |
The answer is almost certainly "no". |
On the second thought, it is possible to preserve set identity and avoid iteration over a large set. See issue8425a.diff attached. It looks like the unit tests don't check identity preservation. I will submit additional tests shortly. |
Note that issue8425a.diff leaves small_set.difference_update(large_dict) unoptimized: $ ./python.exe -m timeit -s "s = {1}; l = dict.fromkeys(range(1000));" "s.difference_update(l)"
1000 loops, best of 3: 842 usec per loop
$ ./python.exe -m timeit -s "s = {1}; l = dict.fromkeys(range(1000));" "s.difference(l)"
100000 loops, best of 3: 13.2 usec per loop It would be easy to add an extra type check, but I noticed that small_set.difference_update(large_dict.viewkeys()) is not optimized either: $ ./python.exe -m timeit -s "s = {1}; l = dict.fromkeys(range(1000));" "s.difference(l.viewkeys())"
1000 loops, best of 3: 842 usec per loop It would be nice if there was a uniform C-API that would allow to uniformly check that an object supports O(1) lookup and invoke such lookup efficiently. I don't think such C-API exists at the moment. I would like to hear what others have to say before adding optimizations to the patch that go beyond the scope of this issue. |
See also bpo-8685. |
Deferring to 3.3. |
Any new logic should make maximum use of existing tools: def __isub__(self, other)
if len(other) > len(self)*8:
other = self & other
. . .
# rest of isub unchanged |
Something like this would also need unit tests? $ ./python.exe -m timeit -s "s= set(range(2000)); l = set(range(20000000)); s=s-l"
10000000 loops, best of 3: 0.0622 usec per loop
[48787 refs]
$ ./python.exe -m timeit -s "s= set(range(2000)); l = set(range(20000000)); s-=l"
10000000 loops, best of 3: 0.0591 usec per loop
[48787 refs] |
Reviewed with Ezio. |
You are measure empty loop. |
woops, sry. Re-posting the benchmark, with three tests: the first one proposed (@abacabadabacaba) with very large sets; another one with smaller sets. $ ./python.exe -m timeit -n 100 -s "s= set(range(2000)); l = set(range(20000000))" "s-=l"
100 loops, best of 3: 9.71 usec per loop
[48787 refs]
$ ./python.exe -m timeit -n 100 -s "s= set(range(1)); l = set(range(20))" "s-=l"
100 loops, best of 3: 0.366 usec per loop
$ hg co -C
$ make -j3 ----[!PATCHED]-------------------------------------------------- $ ./python.exe -m timeit -n 100 -s "s= set(range(2000)); l = set(range(20000000))" "s-=l"
100 loops, best of 3: 665 msec per loop
[48787 refs]
$ ./python.exe -m timeit -n 100 -s "s= set(range(1)); l = set(range(20))" "s-=l"
100 loops, best of 3: 0.849 usec per loop
[48787 refs] |
s is empty set after first loop. Try this: $ ./python.exe -m timeit -n 100 -s "s= set(range(2000)); l = set(range(2000,2000+20000000))" "s-=l" |
Michele, in any case you patch is not preserve set identity. |
What do you mean by "does not preserve set identity"? Because I see: $ ./python.exe
Python 3.3.0rc2+ (default:178f9042af81+, Sep 24 2012, 18:54:31)
[GCC 4.2.1 Compatible Apple Clang 2.1 (tags/Apple/clang-163.7.1)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> a = set(range(1))
[65967 refs]
>>> b = set(range(20))
[65989 refs]
>>> id(a)
4540421032
[65992 refs]
>>> a -= b
[65991 refs]
>>> id(a)
4540421032 |
Sorry, I was wrong. I think that the proposed changes should be applied in set_difference_update_internal() directly. |
Updated. tumbolandia:cpython maker$ hg import --no-commit -f bpo-8425.2.patch && make -j3 >/dev/null 2>/dev/null |
I added a few comments in Rietveld. Did you run benchmarks in debug mode? In order for results to be convenient to compare please sort it by name. |
s/it/them/ |
I find my first patch more readable and efficient, but if these comments are conformant to PEP-7..
|
Please don't apply this until I've signed-off on it. |
It was only a suggestion. Both forms are good enougth.
Yes, I ran it in release mode (gcc, 32-bit Linux) and confirm your results. In general except minor whitespace defects last patch LGTM. |
ping. |
There's no rush on this. I have other work I want to do on set objects before applying further optimizations, so I want to hold off on it for a bit. |
@maker, would you be interested in converting your patch to a Github pull request? Thanks! |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: