-
-
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
Significant Configparser Performance Regression #128641
Comments
@2trvl Thanks for the detailed description and analysis. Adding a cache to the |
@eendebakpt This method doesn't help much, the performance gain is 8.7%. I'll attach a patch made in a hurry, which gives 33%. Although ideally it would be to remove Note that the free-threading version is slowed down a lot by using regular expressions to search for comments and cached_property. Here's how it was in the previous version: Lines 987 to 1005 in 54f7e14
|
Do you mean the issue could arise from
The purpose of the PR was to reduce cyclotomic complexity (essentially have multiple small steps instead of a huge loop block).
I looked at your patch and I think we can perhaps improve it a bit more by computing first |
The patch looks good, except for the part in @2trvl Would you like to make a PR based on the ideas here? |
Free-threading works slower in single-thread, I suppose that a large number of sequential instructions can affect it. Lines 1032 to 1038 in 6116e1b
Apparently, fast creation of immutable objects and writing to their $ python3.13t
1 loop, best of 5: 667 msec per loop
$ python3.13t
1 loop, best of 5: 392 msec per loop GIL Python is not affected by this: $ python3.13
1 loop, best of 5: 343 msec per loop
$ python3.13
1 loop, best of 5: 340 msec per loop
Ok, I'll try to write a decent patch in the next week and maybe create a pull request. |
Bug report
Bug description:
Hello, @jaraco! The following commit 019143f slows down
ConfigParser.read()
from 2 to 6 times._Line
is created many times when reading a file and the same regular expression is compiled for each object_strip_inline
. This amounts to a 60% speed loss. The simplest solution would be to add a__call__
method and preferably create a_Line(object)
when initializingRawConfigParser
with an empty string value. Or abandon the_Line
object altogether.Another 40% of the performance loss comes from using
cached_property
for_Line.clean
(10%), writing to_ReadState
attributes instead of local variables (15%), and breaking up the previous giant loop into new_handle
functions (15%).I discovered this circumstance when writing an update to webbrowser. I needed to parse hundreds of small .desktop files. At first I didn't understand the reason for the increase in execution time between different distributions, so I developed 3 versions of the program:
(M)
Multiprocessing(O)
Original Routine(T)
ThreadingAnd measured their performance using timeit:
As you can see, performance regression is 2-6 times between 3.11 and 3.13. Isolated comparison of the new and old configparser, which verifies the slowdown of free-threading by 6 times:
I also attach a small reproducible test, just a module calling read():
Archive with the above mentioned .desktop files:
shortcuts.zip
And a program for generating your own .desktop paths on Linux/BSD:
Just run this example with different interpreters and you will see the difference:
At this point I leave the solution to this problem to you, as I have no architectural vision of configparser. However, I am willing to offer my help in proposing solutions for Pull Request.
CPython versions tested on:
3.11, 3.12, 3.13
Operating systems tested on:
Linux
The text was updated successfully, but these errors were encountered: