Skip to content

Double linked list implementation for asyncio tasks #107803

Description

@kumaraditya303

Currently asyncio tasks are stored in a Weakset, this is inefficient and in some cases causes bugs because of thread safety (#80788). In terms of memory usage it requires maintaining a full set and their corresponding weakref callback to cleanup objects when deallocated and finalized by the gc. In applications where tasks are created at fast pace this becomes a bottle neck, to mitigate this now asyncio tasks will now be stored in a global double linked of tasks for cases where Task is a subclass of _asyncio.Task in other cases we still rely on the weakset. This reduces the work done by the gc speedups the execution and reduces memory usage. In some of my own benchmarks I have seen 15- 20% improvement and pyperformance benchmarks reflect roughly the same.

https://github.com/faster-cpython/benchmarking-public/blob/main/results/bm-20230805-3.13.0a0-1d32835/bm-20230805-linux-x86_64-kumaraditya303-linked_list-3.13.0a0-1d32835-vs-base.md

Updated: https://github.com/faster-cpython/benchmarking-public/tree/main/results/bm-20240622-3.14.0a0-4717aaa#vs-base

Linked PRs

Activity

  1. added a commit that references this issue on Jun 22, 2024
  2. added
    3.14bugs and security fixes
    and removed
    3.13only security fixes
    on Jun 23, 2024
  3. colesbury commented on Jun 24, 2024

    @colesbury
    Contributor

    I think there are some thread-safety issues with the linked list implementation:

    • It's not going to be thread-safe in the free-threaded build. We can probably add a lock or a critical section.
    • Even with the GIL, the linked list of tasks may be modified while it's being looped over because the GIL can be released in add_one_task.
  4. willingc commented on Jun 24, 2024

    @willingc
    Contributor

    Thanks @colesbury for flagging this.

  5. kumaraditya303 commented on Jun 25, 2024

    @kumaraditya303
    ContributorAuthor

    I am closing this, will track free threaded issues in #120974

  6. moved this from Todo to Done in asyncioon Jun 25, 2024
  7. colesbury commented on Jun 25, 2024

    @colesbury
    Contributor

    @kumaraditya303, can you fix the thread-safety/reentrancy issue that affects the default build (with the GIL)? head can be deallocated while it's being used. It needs to be protected by a Py_INCREF(). This is not specific to the free-threading build.

    TaskObj *tail = &state->asyncio_tasks.tail;
    while (head != tail)
    {
    if (add_one_task(state, tasks, (PyObject *)head, loop) < 0) {
    Py_DECREF(tasks);
    Py_DECREF(loop);
    return NULL;
    }
    head = head->next;
    assert(head != NULL);
    }

  8. added 2 commits that reference this issue on Jun 26, 2024
  9. added 3 commits that reference this issue on Jun 30, 2024
  10. added 3 commits that reference this issue on Jul 11, 2024
  11. added 3 commits that reference this issue on Jul 17, 2024
  12. added a commit that references this issue on Nov 8, 2024
  13. added a commit that references this issue on Dec 8, 2024
  14. added a commit that references this issue on Jan 12, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

Projects

  • Status
    Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions