Comments (5)
@florimondmanca looking for a soft-cancel approach for @pfmoore here agronholm/anyio#333 (comment)
from aiometer.
@graingert Interesting. Would you happen to have a concrete use case to illustrate cases that this would address? Perhaps a code snippet of a precise, stripped-down example would help.
from aiometer.
@graingert Applying your suggestion, I get a ClosedResourceError
on the following example:
import random
import aiometer
import trio
async def process(item: int) -> int:
delay = random.random()
await trio.sleep(delay)
return item
@trio.run
async def main() -> None:
items = list(range(10))
async with aiometer.amap(process, items) as results:
async for r in results:
result = r
break
print(result)
Traceback (most recent call last):
File "/Users/florimond/Developer/florimondmanca-projects/aiometer/debug/example.py", line 14, in <module>
async def main() -> None:
File "/Users/florimond/Developer/florimondmanca-projects/aiometer/venv/lib/python3.9/site-packages/trio/_core/_run.py", line 1932, in run
raise runner.main_task_outcome.error
File "/Users/florimond/Developer/florimondmanca-projects/aiometer/debug/example.py", line 20, in main
break
File "/Users/florimond/.pyenv/versions/3.9.0/lib/python3.9/contextlib.py", line 182, in __aexit__
await self.gen.__anext__()
File "/Users/florimond/Developer/florimondmanca-projects/aiometer/src/aiometer/_impl/amap.py", line 88, in _amap
yield receive_channel
File "/Users/florimond/Developer/florimondmanca-projects/aiometer/venv/lib/python3.9/site-packages/anyio/_backends/_trio.py", line 139, in __aexit__
return await self._nursery_manager.__aexit__(exc_type, exc_val, exc_tb)
File "/Users/florimond/Developer/florimondmanca-projects/aiometer/venv/lib/python3.9/site-packages/trio/_core/_run.py", line 815, in __aexit__
raise combined_error_from_nursery
File "/Users/florimond/Developer/florimondmanca-projects/aiometer/src/aiometer/_impl/amap.py", line 77, in sender
await run_on_each(
File "/Users/florimond/Developer/florimondmanca-projects/aiometer/src/aiometer/_impl/run_on_each.py", line 60, in run_on_each
task_group.start_soon(_worker, async_fn, index, value, config)
File "/Users/florimond/Developer/florimondmanca-projects/aiometer/venv/lib/python3.9/site-packages/anyio/_backends/_trio.py", line 139, in __aexit__
return await self._nursery_manager.__aexit__(exc_type, exc_val, exc_tb)
File "/Users/florimond/Developer/florimondmanca-projects/aiometer/venv/lib/python3.9/site-packages/trio/_core/_run.py", line 815, in __aexit__
raise combined_error_from_nursery
File "/Users/florimond/Developer/florimondmanca-projects/aiometer/src/aiometer/_impl/run_on_each.py", line 24, in _worker
await config.send_to.send(result)
File "/Users/florimond/Developer/florimondmanca-projects/aiometer/venv/lib/python3.9/site-packages/anyio/streams/memory.py", line 191, in send
self.send_nowait(item)
File "/Users/florimond/Developer/florimondmanca-projects/aiometer/venv/lib/python3.9/site-packages/anyio/streams/memory.py", line 173, in send_nowait
raise ClosedResourceError
anyio.ClosedResourceError
I believe this is because now send_channel
and receive_channel
are closed and then sender
tasks are handled, which gives time for a sender
to try to .send()
just before tasks are cancelled, causing a ClosedResourceError
.
See, if I add some prints()
's in _worker()
in run_in_each.py
, just before the call to .send()
:
print(f"sending {result}...")
await config.send_to.send(result)
print(f"sent {result}")
The chain of events is:
sending 3... # first_result
send 3
done # broke out of loop, `aexit` runs
sending 7... # Causes the exception below
[...] ClosedResourceError [...]
Which is why I was asking for a specific use case example. In what situation does this "soft-cancel" apply?
from aiometer.
you would do
async def worker(async_fn, fount, sink):
with fount, sink:
async for item in fount:
result = await async_fn(item)
try:
await sink.send(result)
except anyio.ClosedResourceError:
break
this way closing the pipes cleanly stops the flow of work, but not the work itself
from aiometer.
also anyio 3 supports taskgroup.start so you can limit tasks with:
async def execute_task(semaphore, async_fn, \, *args, task_status, **kwargs):
async with semaphore:
task_status.started()
await async_fn(*args, **kwargs)
async with anyio.create_task_group() as tg:
for task in tasks:
await tg.start(execute_task, task, semaphore)
from aiometer.
Related Issues (9)
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from aiometer.