Hello, Go channels are indeed very similar to asyncio Queues, with some added features like channels being closable. (There is also special syntax in the select statement, `val, ok <- chan`, that will set the `ok` variable to false if the channel has been closed.) A larger difference, I think, is that in Go channels are used practically everywhere, more so than asyncio Queues. They are an abstraction the vast majority of Go concurrency is built upon.
Building this for asyncio tasks, instead of just queues, would be much more useful in Python. Contemplating this some more, I would agree we don't need an async match. A function and some types to match on would probably be enough to get us close to a select statement in a PEP634 Python. I guess the challenge is designing these matchable types for ease of use now, and I need to study the pattern matching PEPs in more detail to be able to contribute here. On one hand, this means this problem can be solved by a third party library. On the other hand, I feel like this would be very useful so it might be worth it to have it somewhere in the stdlib asyncio namespace. Since `asyncio.wait` can yield multiple tasks in the completed set, this would probably have to be wrapped in an `async for`. On Mon, Oct 26, 2020 at 12:33 PM Gustavo Carneiro <gjcarne...@gmail.com> wrote: > It's true that asyncio.wait provides the tools that you need, but it's a > bit clunky to use correctly. > > Maybe would be something along the lines of: > > ------ > queue1 = asyncio.Queue() > queue2 = asyncio.Queue() > ... > get1 = asyncio.create_task(queue1.get()) > get2 = asyncio.create_task(queue2.get()) > await asyncio.wait({get1, get2}, return_when=asyncio.FIRST_COMPLETED) > match [task.done() for task in (get1, get2)]: > case [True, False]: get2.cancel(); item1 = await get1; .... > case [False, True]: get1.cancel(); item2 = await get2; .... > case [True, True]: item1 = await get1; ....; item2 = await get2; .... > ------ > > If asyncio.Queue() is the equivalent of Go channels, perhaps it would be > worth designing a new API for asyncio.Queue, one that is better suited to > the match statement: > > class Queue: > async def read_wait(self) -> 'Queue': > """ > Waits until the queue has at least one item ready to read, without > actually consuming the item. > """ > > Then we could more easily use match statement with multiple queues, thus: > > ------ > async def ready_queue(*queues: asyncio.Queue) -> asyncio.Queue: > """ > Take multiple queue parameters and waits for at least one of them to > have items pending to read, returning that queue. > """ > await asyncio.wait({queue.read_wait() for queue in queues}, > return_when=asyncio.FIRST_COMPLETED) > for queue in queues: > if queue.qsize() > 0: > return queue > > ... > > queue1 = asyncio.Queue() > queue2 = asyncio.Queue() > > ... > > match await ready_queue(queue1, queue2): > case queue1: item1 = queue1.get_nowait(); .... > case queue2: item2 = queue2.get_nowait(); .... > ------ > > Which is less clunky, maybe?... > > The above is not 100% bug free. I think those queue.get_nowait() calls > may still end up raising QueueEmpty exceptions, in case there is another > concurrent reader for those queues. This code would need more work, most > likely. > > In any case, perhaps it's not the match statement that needs to change, > but rather asyncio API that needs to be enhanced. > > > On Sun, 25 Oct 2020 at 01:14, Nick Coghlan <ncogh...@gmail.com> wrote: > >> On Sat., 24 Oct. 2020, 4:21 am Guido van Rossum, <gu...@python.org> >> wrote: >> >>> On Fri, Oct 23, 2020 at 6:19 AM Tin Tvrtković <tinches...@gmail.com> >>> wrote: >>> >>>> Hi, >>>> >>>> first of all, I'm a big fan of the changes being proposed here since in >>>> my code I prefer the 'union' style of logic over the OO style. >>>> >>>> I was curious, though, if there are any plans for the match operator to >>>> support async stuff. I'm interested in the problem of waiting on multiple >>>> asyncio tasks concurrently, and having a branch of code execute depending >>>> on the task. >>>> >>>> Currently this can be done by using asyncio.wait, looping over the >>>> done set and executing an if-else chain there, but this is quite tiresome. >>>> Go has a select statement (https://tour.golang.org/concurrency/5) that >>>> looks like this: >>>> >>>> select { >>>> case <-ch1: >>>> fmt.Println("Received from ch1") >>>> case <-ch2: >>>> fmt.Println("Received from ch2") >>>> } >>>> >>>> Speaking personally, this is a Go feature I miss a lot when writing >>>> asyncio code. The syntax is similar to what's being proposed here. Although >>>> it could be a separate thing added later, async match, I guess. >>>> >>> >>> Hadn't seen this before. You could propose this as a follow-up for 3.11. >>> But aren't Go channels more like asyncio Queues? I guess we'd need way more >>> in terms of a worked-out example (using asyncio code, not Go code). >>> >> >> I think we'd also want to see how far folks get with using guard clauses >> for this kind of "where did the data come from?" check - the only >> specifically asynchronous bit would be the "await multiple tasks" >> operation, and you can already tell asyncio.wait() to return on the first >> completed task rather than waiting for all the results. >> >> Cheers, >> Nick. >> >> >> >>> _______________________________________________ >> Python-Dev mailing list -- python-dev@python.org >> To unsubscribe send an email to python-dev-le...@python.org >> https://mail.python.org/mailman3/lists/python-dev.python.org/ >> Message archived at >> https://mail.python.org/archives/list/python-dev@python.org/message/NQWYLFLGLLCEHAXYHUOXQ3M7IOEL65ET/ >> Code of Conduct: http://python.org/psf/codeofconduct/ >> > > > -- > Gustavo J. A. M. Carneiro > Gambit Research > "The universe is always one step beyond logic." -- Frank Herbert >
_______________________________________________ Python-Dev mailing list -- python-dev@python.org To unsubscribe send an email to python-dev-le...@python.org https://mail.python.org/mailman3/lists/python-dev.python.org/ Message archived at https://mail.python.org/archives/list/python-dev@python.org/message/XNE66KOVLIR5DOSKMQH6BMBRXFAWIPDO/ Code of Conduct: http://python.org/psf/codeofconduct/