3

For the following code using aiohttp:

async def send(self, msg, url):
    async with aiohttp.ClientSession() as session:
        async with session.post(url, data=msg) as response:
            self._msg = response.read()

async def recv(self):
    return await self._msg

It works... Most of the time, but occasionally (frequently, actually) results in various exceptions - usually truncated responses, or a connection already being closed exception.

By contrast, the following works perfectly:

async def send(self, msg, url):
    async with aiohttp.ClientSession() as session:
        async with session.post(url, data=msg) as response:
            self._msg = await response.read()

async def recv(self):
    return self._msg

I would like to know why, as the second version is technically incorrect for my purposes and I need to fix it. (It is incorrect because the recv function might be called before the response has been read)

3
  • "It is incorrect because the recv function might be called before the response has been read" - if it's called before the response has been read, then what's it going to await in the first version? self._msg hasn't been set yet. Commented Sep 14, 2017 at 0:03
  • Exactly, the code I have just happens to never call recv until well after send has completed. But ah, that's a really good point, it turns out that both versions are fundamentally wrong. Can you suggest a fix, while still keeping the 'send' and 'recv' conceptually separate? Commented Sep 14, 2017 at 0:05
  • (To clarify: Whilst I'd appreciate the fix, the real answer I want out of this is to understand the difference between those two code samples) Commented Sep 14, 2017 at 0:16

1 Answer 1

2

with is a context manager, it runs some code before and after any statements within it's block, bookkeeping usually. Meaning, your first recv function most likely awaits on a future that references an already closed connection, or something along these lines.

Let's say you have some code that looks like this:

with open(...) as file:
    file.read()

This is what it does, roughly:

file = open(...)
file.read()
file.close()

And this is the equivalent of what you're doing in your first example:

file = open()
file.close()
...
file.read()
Sign up to request clarification or add additional context in comments.

3 Comments

And that invalidates the future?
I don't know what do you mean by "invalidates the future" exactly, but, basically, this whole thing is not an asyncio issue. It's an issue of reading from a closed socket, or something else that happens deep in the response.read().
Updated the answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.