Open graingert opened 3 years ago
@agronholm I think this is a bug in Trio too - it's just convenient that trio tasks happen not to be allocated in the same location
I think anyio should maintain its own counter of tasks and use a WeakKeyDictionary to lookup tasks in and return that count
But since AnyIO is not responsible for creating all tasks, how would that counter work?
Anyio would need to maintain a WeakKeyDictionary from the concrete task object to a TaskInfo
I don't understand how that relates to counters. What are we counting then?
number of TaskInfo objects created, eg:
@dataclass
class TaskInfo:
...
id = field(default_factory=itertools.count().__next__, init=False)
Ok, but that means that IDs would not necessarily be in the same sequence that the underlying Tasks are created. Are we okay with that?
well they're not currently in sequence, they're just the whim of the allocator
Alright. Then, finally, could there be a situation where an underlying Task could be assigned two artificial IDs through two TaskInfo objects, perhaps when the first TaskInfo has been destroyed? Would that even be a problem?
anyio task ids would be in sequence if TaskInfo objects are created eagerly when the _task_state entry is created.
Alright. Then, finally, could there be a situation where an underlying Task could be assigned two artificial IDs through two TaskInfo objects, perhaps when the first TaskInfo has been destroyed? Would that even be a problem?
Wouldn't the TaskInfo live as long as the Task?
Wouldn't the TaskInfo live as long as the Task?
They currently don't – they are throwaway objects which only live as long the recipient carries them in scope.
Anyio would need to maintain a WeakKeyDictionary from the concrete task object to a TaskInfo
By task do you mean asyncio.Task
, or our own _TaskState
objects? At any rate, how would this work for counting things?
something like this?
_task_infos = WeakKeyDictionary[object, TaskInfo]
_counter = itertools.count()
class TaskInfo:
def __init__(self, task):
self.id = next(_counter)
ti = get_async_lib().extract_task_info(task)
self.parent_id = ti.parent_id
self.coro = ti.coro
def get_current_task_token():
library = sniffio.current_async_library()
if library == "trio":
return trio.lowlevel.current_task()
elif library == "asyncio":
return asyncio.current_task()
else:
raise RuntimeError("unsupported")
def get_current_task():
task = get_current_task_token()
try:
return _task_infos[task]
except KeyError:
_task_infos[task] = task_info = TaskInfo(task)
return task_info
Right, if we keep the TaskInfo
objects around, then I can see a counter system working. I was just hoping we wouldn't have to.
This is a problem in anyio because TaskInfo's
__eq__
goes on to compare dead object IDs