Skip to content
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

body thread helpers #3205

Merged
merged 33 commits into from
Nov 30, 2018
Merged

Conversation

thehesiod
Copy link
Contributor

@thehesiod thehesiod commented Aug 20, 2018

work on resolving #3201

@thehesiod
Copy link
Contributor Author

I also fixed some subclass methods which didn't match the parent class parameter declarations.

aiohttp/web_response.py Outdated Show resolved Hide resolved
aiohttp/web_response.py Outdated Show resolved Hide resolved
if self._body_payload or self._chunked:
return super()._do_start_compression(coding)
if coding != ContentCoding.identity:
# Instead of using _payload_writer.enable_compression,
# compress the whole body
zlib_mode = (16 + zlib.MAX_WBITS
if coding.value == 'gzip' else -zlib.MAX_WBITS)
if len(self._body) > _BODY_LENGTH_THREAD_CUTOFF:
loop = asyncio.get_event_loop()
await loop.run_in_executor(None,
Copy link
Member

Choose a reason for hiding this comment

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

What if default executor will be process one? That may hurt instead of making things better.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

that's already a problem in aiohttp's use of getaddrinfo

aiohttp/web_response.py Outdated Show resolved Hide resolved
aiohttp/web_response.py Outdated Show resolved Hide resolved
@codecov-io
Copy link

codecov-io commented Aug 22, 2018

Codecov Report

Merging #3205 into master will decrease coverage by 0.06%.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #3205      +/-   ##
==========================================
- Coverage   98.01%   97.94%   -0.07%     
==========================================
  Files          44       44              
  Lines        8511     8522      +11     
  Branches     1382     1383       +1     
==========================================
+ Hits         8342     8347       +5     
- Misses         70       74       +4     
- Partials       99      101       +2
Impacted Files Coverage Δ
aiohttp/web_response.py 98.41% <100%> (+0.03%) ⬆️
aiohttp/tcp_helpers.py 90% <0%> (-6.67%) ⬇️
aiohttp/web_fileresponse.py 96.51% <0%> (-1.75%) ⬇️
aiohttp/client_reqrep.py 97.28% <0%> (-0.16%) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 0c54bef...fc57bcb. Read the comment docs.

@thehesiod
Copy link
Contributor Author

hrm, codecov stuck

…helpers

# Conflicts:
#	aiohttp/web_response.py
thehesiod added a commit to thehesiod-forks/aiohttp that referenced this pull request Sep 24, 2018
@thehesiod
Copy link
Contributor Author

thehesiod commented Sep 25, 2018

failed due to: The job exceeded the maximum log length, and has been terminated.

another error: aiohttp.client_exceptions.ClientConnectorSSLError: Cannot connect to host 127.0.0.1:36583 ssl:None [[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate (_ssl.c:871)] doesn't seem like I caused these

if asyncio.iscoroutinefunction(dumps):
text = await dumps(data)
elif executor_body_size is not None and \
len(data) > executor_body_size:
Copy link
Member

Choose a reason for hiding this comment

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

I was curious to try your patch "at home" and found that this check actually ruins all the idea. Imagine the following data: {"users": [{"id": 1, "name": ..., ...few more 50 fields}, ..., ..about 100 more items]}. In this case len will return 1 all the time, but response data is big enough.

Instead, I was able to make async dump easily in place where I'm sure big data will happens and this async dump will be useful. On my application side it's easy to do: I know my data and how big it could be. On aiohttp side it's hard to figure out without tricky inspections which will may negotiate all the profit of this feature.

Copy link
Member

Choose a reason for hiding this comment

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

M/b try (recursive) sizeof?

Copy link
Member

Choose a reason for hiding this comment

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

sizeof will require you somehow convert objects memory usage into string length, which wouldn't be trivial. And all this complexity just to prevent users explicitly define behaviour on their side with two lines of code?

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, I agree with users needing to just opt-in by themselves.
As for converting to string length, it's not needed, just bytes it occupies in memory would be enough :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

hah! wow that was a huge oversight, thanks...however thinking about this, I still need something like a sizeof, I don't know how large the object is without doing the dump ;) I'll have to think about this for a bit

Copy link
Contributor Author

Choose a reason for hiding this comment

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

removing this from this PR, thanks guys and sorry for the distraction...however it remains a problem to be solved. Given a dict, to programmatically determine if it should be dumped in a thread or not. I suppose you just need to decide if you always want to run it in a thread or not.

Copy link
Member

Choose a reason for hiding this comment

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

No worries :)
One of the solutions might be recursively accumulating the size of stuff in the nested object with interruption of the process once reached some threshold as a flag for compression being needed as an optimization.

@asvetlov
Copy link
Member

Please merge with master.
I've reduced output log size (I hope) by disabling pytest-sugar plugin.
The plugin is pretty nice, I'm still using it locally but it writes to many terminal control symbols to make the output colorized and interactive.

@webknjaz
Copy link
Member

webknjaz commented Oct 1, 2018

@asvetlov sugar is not the issue. The issue is that you run a lot of tests, which I'm trying to address for a long time now. You should be running test suite in just one mode per job, it'd help dramatically. That's one of the reasons of me pushing towards using tox or smth similar to unify testing layer, maybe parallelise it + possibly distribute across CIs.

@webknjaz
Copy link
Member

webknjaz commented Oct 1, 2018

@thehesiod this PR needs conflict resolution (rebase or merge)

…helpers

# Conflicts:
#	tests/test_web_response.py
@thehesiod
Copy link
Contributor Author

ok I think I fixed it, followed: https://stackoverflow.com/a/23668025. Not sure how that happened as I never touched the submodules

compressobj.flush()
if self._zlib_thread_size is not None and \
len(self._body) > self._zlib_thread_size:
await asyncio.get_event_loop().run_in_executor(
Copy link
Member

Choose a reason for hiding this comment

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

Wouldn't it be better to have a thread pool in place?

Copy link
Member

Choose a reason for hiding this comment

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

I think it would. If someone will set default executor as mutiprocessing one he will get very surprised by aiohttp behaviour. However, inplace thread pool will cause DoS situation - you need to limit overall threads by some sane number.

Copy link
Member

Choose a reason for hiding this comment

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

Multiprocessing pool as default is deprecated by asyncio: it doesn't work well with API like loop.getaddrinfo() anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Perhaps ability to pass in thread pool? This can get complicated later if you want to support multiple pools

Copy link
Member

Choose a reason for hiding this comment

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

Make sense. Feel free to update the PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@asvetlov added

@asvetlov
Copy link
Member

Sorry, I broke unit tests trying to resolve merge conflicts.
@thehesiod would you take a look?

Copy link
Member

@asvetlov asvetlov left a comment

Choose a reason for hiding this comment

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

Thanks, very close to finish.

Please add versionadded directives in doc.

Adding a test with passing explicit executor would be nice to have also.

@@ -830,6 +831,10 @@ Response
:param str charset: response's charset. ``'utf-8'`` if *text* is
passed also, ``None`` otherwise.

:param int zlib_executor_size: length in bytes which will trigger zlib compression
of body to happen in an executor

Copy link
Member

Choose a reason for hiding this comment

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

Please insert .. versionadded:: 3.5 directive here.

Copy link
Member

Choose a reason for hiding this comment

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

aiohttp 3.5.0 was not released yet, only 3.5.0 alpha 0.
So please use just 3.5, the last zero should be omitted.

docs/web_reference.rst Show resolved Hide resolved
@@ -830,6 +831,10 @@ Response
:param str charset: response's charset. ``'utf-8'`` if *text* is
passed also, ``None`` otherwise.

:param int zlib_executor_size: length in bytes which will trigger zlib compression
of body to happen in an executor

Copy link
Member

Choose a reason for hiding this comment

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

aiohttp 3.5.0 was not released yet, only 3.5.0 alpha 0.
So please use just 3.5, the last zero should be omitted.


:param int zlib_executor: executor to use for zlib compression
.. versionadded:: 3.5.1
Copy link
Member

Choose a reason for hiding this comment

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

3.5 as above.

Copy link
Member

@asvetlov asvetlov left a comment

Choose a reason for hiding this comment

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

Perfect!
Thank you for the patience!

@asvetlov asvetlov merged commit 8c5baa3 into aio-libs:master Nov 30, 2018
@thehesiod thehesiod deleted the thehesiod-thread-helpers branch November 30, 2018 21:34
@thehesiod
Copy link
Contributor Author

ty guys for the help!

@lock
Copy link

lock bot commented Nov 30, 2019

This thread has been automatically locked since there has not been
any recent activity after it was closed. Please open a new issue for
related bugs.

If you feel like there's important points made in this discussion,
please include those exceprts into that new issue.

@lock lock bot added the outdated label Nov 30, 2019
@lock lock bot locked as resolved and limited conversation to collaborators Nov 30, 2019
@psf-chronographer psf-chronographer bot added the bot:chronographer:provided There is a change note present in this PR label Nov 30, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bot:chronographer:provided There is a change note present in this PR outdated
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants