Skip to content

Commit 9015e7d

Browse files
committed
Revert "Add a new async iterable select() function"
Sadly the generator approach doesn't work because of limitations in how Python handles the `yield` statement and breaking out from a `async for` for loop (actually this applies to sync generators too). When the loop is broken, the control is never passed back to the async genreator, so the `finally` block is never executed (at least not until the end of the program, where dangling generators are cleared). Because of this, we will need to use a class instead, and to make it easy to guarantee avoiding leaking resources (tasks), we make it an async context managaer and an async iterator. This reverts commit 2764d01. Example: ```python import asyncio from typing import AsyncIterator was_gen_finalized: bool = False async def gen() -> AsyncIterator[int]: try: print("gen") yield 1 finally: global was_gen_finalized was_gen_finalized = True print("gen finally") async def main() -> None: global was_gen_finalized print("1. without break") async for i in gen(): print(i) print(f" end of loop: {was_gen_finalized=}") was_gen_finalized = False print("------------------") print("2. with break") async for i in gen(): print(i) break print(f" end of loop: {was_gen_finalized=}") was_gen_finalized = False print("------------------") print("2. with exception") try: async for i in gen(): print(i) raise Exception("Interrupted by exception") except Exception: pass print(f" end of loop: {was_gen_finalized=}") was_gen_finalized = False print() print("END of main") asyncio.run(main()) print(f"END of asyncio.run(): {was_gen_finalized=}") ``` This program prints: ``` 1. without break gen 1 gen finally end of loop: was_gen_finalized=True ------------------ 2. with break gen 1 end of loop: was_gen_finalized=False ------------------ 2. with exception gen 1 end of loop: was_gen_finalized=False END of main gen finally gen finally END of asyncio.run(): was_gen_finalized=True ``` Signed-off-by: Leandro Lucarella <[email protected]>
1 parent b000713 commit 9015e7d

File tree

2 files changed

+4
-412
lines changed

2 files changed

+4
-412
lines changed

src/frequenz/channels/util/__init__.py

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -26,24 +26,13 @@
2626
* [Select][frequenz.channels.util.Select]: A helper to select the next
2727
available message for each [receiver][frequenz.channels.Receiver] in a group
2828
of receivers.
29-
30-
* [select][frequenz.channels.util.select]: A function to iterate over a group
31-
of [receivers][frequenz.channels.Receiver] and select the next available value.
3229
"""
3330

3431
from ._event import Event
3532
from ._file_watcher import FileWatcher
3633
from ._merge import Merge
3734
from ._merge_named import MergeNamed
38-
from ._select import (
39-
Select,
40-
Selected,
41-
SelectError,
42-
SelectErrorGroup,
43-
UnhandledSelectedError,
44-
select,
45-
selected_from,
46-
)
35+
from ._select import Select
4736
from ._timer import (
4837
MissedTickPolicy,
4938
SkipMissedAndDrift,
@@ -58,15 +47,9 @@
5847
"Merge",
5948
"MergeNamed",
6049
"MissedTickPolicy",
50+
"Timer",
6151
"Select",
62-
"SelectError",
63-
"SelectErrorGroup",
64-
"Selected",
6552
"SkipMissedAndDrift",
6653
"SkipMissedAndResync",
67-
"Timer",
6854
"TriggerAllMissed",
69-
"UnhandledSelectedError",
70-
"select",
71-
"selected_from",
7255
]

0 commit comments

Comments
 (0)