diff options
| author | bd <bdunahu@operationnull.com> | 2025-07-21 13:25:56 -0600 |
|---|---|---|
| committer | bd <bdunahu@operationnull.com> | 2025-07-21 13:25:56 -0600 |
| commit | 487c77a96504c0178581a7a4bb7e9cd66783548f (patch) | |
| tree | 67bb104ce5fe7238546001a47a85b8aaafc042a1 | |
| parent | 83e88319b72df01fa70e6bf3a020ab745cdef661 (diff) | |
Update comments reflecting on asyncio.gather and task groups
| -rwxr-xr-x | aergia/aergia.py | 3 | ||||
| -rw-r--r-- | t/test_functionality.py | 79 |
2 files changed, 59 insertions, 23 deletions
diff --git a/aergia/aergia.py b/aergia/aergia.py index 83cf0fa..b10c82b 100755 --- a/aergia/aergia.py +++ b/aergia/aergia.py @@ -251,7 +251,6 @@ class Aergia(object): ret = None while curr: frame = getattr(curr, 'cr_frame', None) - # print(frame) if frame and Aergia.should_trace(frame.f_code.co_filename): ret = frame curr = getattr(curr, 'cr_await', None) @@ -260,7 +259,7 @@ class Aergia(object): @staticmethod def should_trace(filename): '''Returns FALSE if filename is uninteresting to the user. - Don't depend on this.''' + Don't depend on this. It's good enough for testing.''' # FIXME Assume GuixSD. Makes filtering easy if '/gnu/store' in filename: return False diff --git a/t/test_functionality.py b/t/test_functionality.py index 63863cf..75f0137 100644 --- a/t/test_functionality.py +++ b/t/test_functionality.py @@ -3,6 +3,10 @@ import asyncio import threading +class TerminateTaskGroup(Exception): + '''Exception raised to terminate a task group.''' + + class BasicUsage(utils.AergiaUnitTestCase): def test_asyncless(self): @@ -55,7 +59,10 @@ class BasicUsage(utils.AergiaUnitTestCase): self.assertFuncContains('b', [self.expected_samples(delay * 3)], samples) - # TODO samples from gather all execution time, should we trace this? + # the gather function is technically waiting for all tasks to finish. + # This might be seen as unintuitive though I don't want to bias the + # results by adding logic to add artificial consistency. + # profiling does not mean obscuring implementation details. self.assertFuncContains('a', [self.expected_samples(delay)], samples) def test_subthread_task(self): @@ -75,7 +82,7 @@ class BasicUsage(utils.AergiaUnitTestCase): self.assertFuncContains('c', [], samples) self.assertFuncContains('b', [self.expected_samples(delay * 3)], samples) - # TODO samples from gather all execution time, should we trace this? + # see comment on `test_simultaneous_tasks'. self.assertFuncContains('a', [self.expected_samples(delay)], samples) def test_eager_task(self): @@ -92,6 +99,31 @@ class BasicUsage(utils.AergiaUnitTestCase): samples = self.Aergia.get_samples() self.assertFuncContains('a', [self.expected_samples(delay)], samples) + def test_async_eager_scheduled_woven(self): + d1 = 0.2 + d2 = 0.3 + d3 = 0.2 + d4 = 0.1 + + async def a(): + await asyncio.sleep(d1) + proc = await asyncio.create_subprocess_shell(f'sleep {d2}') + await proc.communicate() + await asyncio.sleep(d3) + proc = await asyncio.create_subprocess_shell(f'sleep {d4}') + await proc.communicate() + + self.Aergia.start() + asyncio.run(a()) + self.Aergia.stop() + + samples = self.Aergia.get_samples() + self.assertFuncContains('a', [self.expected_samples(d1), + self.expected_samples(d2), + self.expected_samples(d3), + self.expected_samples(d4), + ], samples) + def test_async_generator(self): delay = 0.2 num_times = 10 @@ -111,8 +143,8 @@ class BasicUsage(utils.AergiaUnitTestCase): self.Aergia.stop() samples = self.Aergia.get_samples() - # TODO can we make these results more intuitive? - # async generators also do not work at all with yappi. + # TODO I do not think async generators report correctly. + # also does not work at all with yappi. # doing so would be unique to this profiler. # self.assertFuncContains('b', @@ -142,8 +174,8 @@ class BasicUsage(utils.AergiaUnitTestCase): self.Aergia.stop() samples = self.Aergia.get_samples() - # TODO can we make these results more intuitive? - # async generators also do not work at all with yappi. + # TODO I do not think async generators report correctly. + # also does not work at all with yappi. # doing so would be unique to this profiler. self.assertFuncContains('b', [], samples) @@ -192,28 +224,32 @@ class BasicUsage(utils.AergiaUnitTestCase): self.assertFuncContains('d', [self.expected_samples(d1)], samples) self.assertFuncContains('c', [self.expected_samples(d2)], samples) self.assertFuncContains('b', [self.expected_samples(d3)], samples) - # TODO where does this come from? + # the task group is technically waiting for all tasks to finish. + # same as task.gather + # This might be seen as unintuitive, (especially considering how + # the next test works), though I don't want to bias the results + # by adding logic to add artificial consistency. + # Both are reporting correctly. self.assertFuncContains('a', [self.expected_samples(d2)], samples) def test_task_groups_cancel(self): d1 = 0.1 - d2 = 0.2 - d3 = 0.3 - async def d(): await asyncio.sleep(d1) + d2 = 0.3 + d3 = 0.2 + async def d(): raise TerminateTaskGroup - async def c(): - await asyncio.sleep(d2) - 1 / 0 # crash + async def c(): await asyncio.sleep(d1) - async def b(): await asyncio.sleep(d3) + async def b(): await asyncio.sleep(d2) async def a(): try: async with asyncio.TaskGroup() as tg: - tg.create_task(d()) tg.create_task(c()) tg.create_task(b()) - except: + await asyncio.sleep(d3) + tg.create_task(d()) + except* TerminateTaskGroup: pass self.Aergia.start() @@ -222,8 +258,9 @@ class BasicUsage(utils.AergiaUnitTestCase): samples = self.Aergia.get_samples() - self.assertFuncContains('d', [self.expected_samples(d1)], samples) - self.assertFuncContains('c', [self.expected_samples(d2)], samples) - self.assertFuncContains('b', [self.expected_samples(d2)], samples) - # TODO where does this come from? - self.assertFuncContains('a', [self.expected_samples(d2)], samples) + self.assertFuncContains('d', [], samples) + self.assertFuncContains('c', [self.expected_samples(d1)], samples) + self.assertFuncContains('b', [self.expected_samples(d3)], samples) + # this time is attached to the sleep call itself. Aergia's print + # function would confirm this! + self.assertFuncContains('a', [self.expected_samples(d3)], samples) |
