8000 document that sprite groups are ordered in python 3.6 and above by zoldalma999 · Pull Request #2336 · pygame/pygame · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

document that sprite groups are ordered in python 3.6 and above #2336

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

Merged
merged 2 commits into from
Dec 22, 2020
Merged

document that sprite groups are ordered in python 3.6 and above #2336

merged 2 commits into from
Dec 22, 2020

Conversation

zoldalma999
Copy link
Contributor

Related to #1951
I will do benchmarks if the tests pass.

@illume
Copy link
Member
illume commented Nov 21, 2020

Apart from writing some micro benchmarks, one way to do sprite benchmarks is with multiple runs of python -m pygame.examples.testsprite. Note, there are different command line options (sorry, it's not using a library for this, 8000 so viewing the source is the only way to get them). This lets you test with different sprite and group classes, and with different numbers of sprites.

It's probably good to also test with something else, like with a game that uses sprites.

@MyreMylar
Copy link
Contributor

This implementation seems very sensible to me. I believe regular python dicts will be slightly faster (from looking over other benchmarking data) but it's likely that if you care that much about speed and are using sprites you will be using python 3.7+ and if you care about speed to that degree and are using python 2.7 you probably aren't using pygame's sprite module anyway.

Basically I feel like the consistent behaviour across versions will be more widely useful than slightly slowing down performance of older python 3 versions and 2.7 users using sprites.

I expect one day a C version of a sprite group could do some of the looping draw to blit parts a bit faster but that would likely be part of a wider sprite module refactor (that may become dominated by sorting out texture sharing and that sort of thing anyway).

@illume
Copy link
Member
illume commented Nov 21, 2020

Let's just benchmark it, and then we can see if the trade off is worth it.

@zoldalma999
Copy link
Contributor Author

I started the benchmarking, will try to finish it today.
Also using python 3.6.8 it seems like it is already sorted (in the original it also says that he used 3.6.9) so it might not be exactly 3.7.0. I will try to find the last version that does not sort it using normal dict.

@MyreMylar
Copy link
Contributor
MyreMylar commented Nov 21, 2020

If you read this hacker news thread:

https://news.ycombinator.com/item?id=22266173

it seems that the implementation was changed for dictionaries to be insertion ordered for CPython in 3.6. But the change wasn't made to the actual python language spec until 3.7 So you could still have valid 3.6 python code with unordered dictionaries if it was running on a non-CPython interpreter.

@illume
Copy link
Member
illume commented Nov 21, 2020

Cool, thanks.

If you add a unit test for the sorting, then the CI can run on different versions of python to confirm the ordering.

There's some other dict uses in sprite.py that are likely affected by the same issue.

Some microbenchmark timings for dict assignment in python 3.8 on mac.

In [1]: %timeit dict()
126 ns ± 1.16 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

In [2]: %timeit {}
23.5 ns ± 0.123 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

In [3]: %timeit {}
23.5 ns ± 0.123 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

In [4]: from collections import OrderedDict

In [5]: %timeit OrderedDict()
121 ns ± 0.351 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

In [6]: %timeit OrderedDict()
120 ns ± 0.597 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

In [7]: %timeit dict()
125 ns ± 0.654 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

In [8]: %timeit dict()
126 ns ± 1.23 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

In [9]: %timeit OrderedDict()
121 ns ± 0.64 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)


In [12]: import timeit

In [13]: s= """
    ...: if USE_ORDEREDDICT:
    ...:     a = OrderedDict()
    ...: else:
    ...:     a = {}
    ...: """

In [21]: timeit.timeit(s, setup="from collections import OrderedDict", globals={"USE_ORDEREDDICT":1})
Out[21]: 0.1377905770000325

In [22]: timeit.timeit(s, setup="from collections import OrderedDict", globals={"USE_ORDEREDDICT":0})
Out[22]: 0.04726486300000943

In [23]: timeit.timeit(s, setup="from collections import OrderedDict", globals={"USE_ORDEREDDICT":0})
Out[23]: 0.047848736999981156

In [24]: timeit.timeit("a={}", setup="from collections import OrderedDict", globals={"USE_ORDEREDDICT":0})
Out[24]: 0.02688187400002562

In [25]: timeit.timeit("a={}", setup="from collections import OrderedDict", globals={"USE_ORDEREDDICT":0})
Out[25]: 0.02763441999996985

@zoldalma999
Copy link
Contributor Author
zoldalma999 commented Nov 21, 2020
  • I used pygame.examples.testsprite
  • I used two python versions(2.7.17, 3.4.4).
  • I ran every test three times to be a bit more accurate
  • Every number is the fps I got from the test

Python 2.7.17:

Flag(s) With orderedDicts Without orderedDicts
No flag 1858, 1869, 1857 2624, 2368, 2449
-noupdate_rects 1897, 1864, 1902 2068, 2063, 2066
-scaled 1412, 1422, 1394 1615, 1586, 1604
-fullscreen 1912, 1856, 1874 2452, 2408, 2529
-alpha 1827, 1839, 1819 2293, 2270, 2338
-scaled -fullscreen 1409, 1422, 1407 1537, 1545, 1585

Python 3.4.4:

Flag(s) With orderedDicts Without orderedDicts
No flag 1731, 1742, 1716 2193, 2199, 2178
-noupdate_rects 1746, 1715, 1695 1975, 1974, 1962
-scaled 1316, 1311, 1307 1491, 1489, 1505
-fullscreen 1694, 1713, 1709 2130, 2155, 2170
-alpha 1713, 1715, 1708 2086, 2039, 2097
-scaled -fullscreen 1325, 1327, 1299 1479, 1447, 1470

@MyreMylar
Copy link
Contributor
MyreMylar commented Nov 21, 2020

Looks like the using the basic python dict runs about 10% - 30% faster on these tests. Not super great for OrderedDict.

Perhaps if we do go ahead with this we should also add an environment variable that allows users to override USE_ORDEREDDICT. Something like PYGAME_ALWAYS_USE_ORDERED_SPRITE_DICT = '0' and default it to '1'?

@illume
Copy link
Member
illume commented Nov 23, 2020

Thanks for testing that @zoldalma999.

I'd like to repeat the tests on some slower gfx hardware, and another sprite using game just to be sure. I'll get around to it in a few days.

If it's a similar result, I'd suggest we don't make the change. Instead, people who care could use a mixin class or a monkey patch.

@zoldalma999
Copy link
Contributor Author

If we dont add orderedDicts i would still edit the docs so it tells you which python version you can use to have an ordered group since currently this is whats in the docs:

The Sprites in the Group are not ordered, so drawing and iterating the Sprites is in no particular order.

Perhaps something like this

The Sprites in the Group are ordered only on python 3.7 or higher. Below python 3.7 drawing and iterating over the Sprites is in no particular order.

would be nicer.

@illume
Copy link
Member
illume commented Dec 21, 2020

I think we should not include this change, just because of the noticeable performance penalty. The doc change is a good idea. I'll also note in the issue that a subclass of the group that uses an ordered dict can be used for people who want to rely on ordering in cpython 2.7.

The Sprites in the Group are ordered only on python 3.6 and higher. Below python 3.6 drawing and iterating over the Sprites is in no particular order.

Yeah, that text would be nicer. Note however, I think we should use 3.6. Since although it wasn't guaranteed as part of a specification, 3.6 was ordered.

If you agree, we can close this PR and I'll make the notes in the issue about the changes. If you instead think the benefit of ordering outweighs the performance penalty I'm open to including the PR. Can I leave the decision to you @zoldalma999 ?

Copy link
Member
@illume illume left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@zoldalma999
Copy link
Contributor Author

I think either we should ditch it or make it optional and default to off. What MyreMylar suggested seems like a good way if we want to chose the latter.

@illume
Copy link
Member
illume commented Dec 21, 2020

Ok. Well, ditching it seems the easier option for now :)

@illume
Copy link
Member
illume commented Dec 22, 2020

Thanks @zoldalma999

@illume illume merged commit 7b63172 into pygame:main Dec 22, 2020
@illume illume changed the title Use orderedDicts in groups document that sprite groups are ordered in python 3.6 and above Dec 23, 2020
@illume illume added sprite pygame.sprite docs labels Dec 23, 2020
@illume illume added this to the 2.0.1 milestone Aug 21, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs sprite pygame.sprite
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants
0