Skip to content

[Aio] Accepts normal iterable of request messages#22580

Merged
lidizheng merged 3 commits intogrpc:masterfrom
lidizheng:aio-iterator
Apr 6, 2020
Merged

[Aio] Accepts normal iterable of request messages#22580
lidizheng merged 3 commits intogrpc:masterfrom
lidizheng:aio-iterator

Conversation

@lidizheng
Copy link
Copy Markdown
Contributor

@lidizheng lidizheng commented Apr 3, 2020

To improve the usability of our library, this PR enables stream-unary and stream-stream RPCs to accept normal iterable of request messages, instead of only allowing async iterable. So, it is backward compatible.

We was in favor of using async generator and trying to publicize it. However, there are several issues with it:

  1. Async generator doesn't have good API as asyncio.Task(no cancel(), done(), cancelled(), etc.);
  2. There is no aiter(...) built-in function (I don't understand CPython team);
  3. It requires extra effort of memory management otherwise the interpreter generates warning (see code).

Also, accepting iterables makes non-complex logic much easier (see example).

@lidizheng lidizheng added lang/Python release notes: yes Indicates if PR needs to be in release notes labels Apr 3, 2020
@lidizheng lidizheng marked this pull request as ready for review April 3, 2020 21:06
@lidizheng lidizheng requested review from gnossen and pfreixes April 3, 2020 21:06
ChannelArgumentType = Sequence[Tuple[str, Any]]
EOFType = type(EOF)
DoneCallbackType = Callable[[Any], None]
RequestIterableType = Union[Iterable[Any], AsyncIterable[Any]]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks like a good solution. 👍

if inspect.isasyncgen(request_iterator):
async for request in request_iterator:
await self._write(request)
await self._done_writing()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nit: await self._done_writing() is common to both branches.

# Prepares the request
payload = messages_pb2.Payload(body=b'\0' * _REQUEST_PAYLOAD_SIZE)
request = messages_pb2.StreamingInputCallRequest(payload=payload)
requests = [request] * _NUM_STREAM_RESPONSES
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Very nice. I can especially see this coming in handy for unit tests.

@pfreixes
Copy link
Copy Markdown
Collaborator

pfreixes commented Apr 4, 2020

Thanks for the change, out of curiosity and with regards of your points:

Async generator doesn't have good API as asyncio.Task(no cancel(), done(), cancelled(), etc.);

I guess that the same as a coroutine, a coroutine does not provide either a good API, and its sufficient when the core is instantiated and executed within the scope of a task. If you want to run it separately you have to wrap the coro into a Task object.

I would expect the same for the async generator.

There is no aiter(...) built-in function (I don't understand CPython team);

Your proposal would be having an aiter implementation which would allow you to wrap a none asynchronous iterator for making asynchronously? For reducing the burden of having to use one or another pattern depending on what iterator are you targeting?

@lidizheng
Copy link
Copy Markdown
Contributor Author

For the first point, as you mentioned, the async generator API will be much better if there is a Task-like wrapper. cancel() is easy to implement, but done() and cancelled() aren't. In order to get the state of the generator, one must call asend() or anext(). Then the progress of generator changed.

For the second point, aiter is promised in PEP525, but got dropped out of implementation since 3.6. Yes, I hope Python has a simple way to make normal iterator async.

@lidizheng lidizheng merged commit 4d91e53 into grpc:master Apr 6, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lang/Python release notes: yes Indicates if PR needs to be in release notes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants