X Tutup
The Wayback Machine - https://web.archive.org/web/20220512051229/https://github.com/python/cpython/issues/86251
Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add dedicated slot for sending values #86251

Open
vladima mannequin opened this issue Oct 19, 2020 · 19 comments
Open

Add dedicated slot for sending values #86251

vladima mannequin opened this issue Oct 19, 2020 · 19 comments
Labels
3.10 interpreter-core performance

Comments

@vladima
Copy link
Mannequin

@vladima vladima mannequin commented Oct 19, 2020

BPO 42085
Nosy @encukou, @asvetlov, @1st1, @pablogsal, @miss-islington, @vladima, @sweeneyde, @iritkatriel, @Martmists-GH
PRs
  • #22780
  • #23237
  • #23374
  • #25465
  • #26453
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = None
    closed_at = None
    created_at = <Date 2020-10-19.19:38:16.972>
    labels = ['interpreter-core', '3.10', 'performance']
    title = 'Add dedicated slot for sending values'
    updated_at = <Date 2021-08-26.09:51:38.507>
    user = 'https://github.com/vladima'

    bugs.python.org fields:

    activity = <Date 2021-08-26.09:51:38.507>
    actor = 'pablogsal'
    assignee = 'none'
    closed = False
    closed_date = None
    closer = None
    components = ['Interpreter Core']
    creation = <Date 2020-10-19.19:38:16.972>
    creator = 'v2m'
    dependencies = []
    files = []
    hgrepos = []
    issue_num = 42085
    keywords = ['patch']
    message_count = 19.0
    messages = ['378999', '380706', '380708', '380750', '380763', '380765', '380770', '380772', '380777', '381369', '381375', '381381', '394736', '394737', '397872', '400045', '400299', '400310', '400330']
    nosy_count = 9.0
    nosy_names = ['petr.viktorin', 'asvetlov', 'yselivanov', 'pablogsal', 'miss-islington', 'v2m', 'Dennis Sweeney', 'iritkatriel', 'martmists']
    pr_nums = ['22780', '23237', '23374', '25465', '26453']
    priority = 'normal'
    resolution = None
    stage = 'resolved'
    status = 'open'
    superseder = None
    type = 'performance'
    url = 'https://bugs.python.org/issue42085'
    versions = ['Python 3.10']

    @vladima
    Copy link
    Mannequin Author

    @vladima vladima mannequin commented Oct 19, 2020

    https://bugs.python.org/issue41756 has introduced PyIter_Send as a common entrypoint for sending values however currently fast path that does not use StopIteration exception is only available for generators/coroutines. It would be quite nice if this machinery was extensible and other types (both internal and 3rd party) could opt-in into using exception-free way of returning values without needing to update the implementation of PyIter_Send. One way of solving this is adding a new slot with a signature that matches PyIter_Send. With it:

    • it should be possible to implement this slot for coroutines/generators and remove special casing for them in PyIter_Send
    • provide implementation for this slot for internal types (i.e. FutureIter in _asynciomodule.c) - results of this experiment can be found below
    • enable external native extensions to provide efficient implementation of coroutines (i.e. Cython could benefit from it)

    Microbenchmark to demonstrate the difference of accessing the value of fulfiled Future without and with dedicated slot:

    import asyncio
    import time
    
    N = 100000000
    
    async def run():
        fut = asyncio.Future()
        fut.set_result(42)
    
        t0 = time.time()
        for _ in range(N):
            await fut
        t1 = time.time()
        print(f"Time: {t1 - t0} s")
    
    asyncio.run(run())
    

    Time: 8.365560054779053 s - without the slot
    Time: 5.799655914306641 s - with the slot

    @vladima vladima mannequin added 3.10 interpreter-core performance labels Oct 19, 2020
    @1st1
    Copy link
    Member

    @1st1 1st1 commented Nov 10, 2020

    New changeset 1e996c3 by Vladimir Matveev in branch 'master':
    bpo-42085: Introduce dedicated entry in PyAsyncMethods for sending values (bpo-22780)
    1e996c3

    @1st1
    Copy link
    Member

    @1st1 1st1 commented Nov 10, 2020

    Vladimir, please do a follow up PR documenting Py_TPFLAGS_HAVE_AM_SEND.

    @vstinner
    Copy link
    Member

    @vstinner vstinner commented Nov 11, 2020

    New changeset 1e996c3 by Vladimir Matveev in branch 'master':

    This change introduced big reference leaks:

    4 tests failed:
    test_asyncgen test_asyncio test_coroutines test_unittest

    Example:

    $ ./python -m test test_asyncgen -R 3:3 -m test.test_asyncgen.AsyncGenAsyncioTest.test_async_gen_asyncio_03
    (...)
    test_asyncgen leaked [63, 63, 63] references, sum=189
    (...)

    Please fix the leak, or revert if nobody is avaible to fix it:
    https://pythondev.readthedocs.io/ci.html#revert-on-fail

    @asvetlov
    Copy link
    Contributor

    @asvetlov asvetlov commented Nov 11, 2020

    Investigating. The test leaks a future instance.

    @asvetlov
    Copy link
    Contributor

    @asvetlov asvetlov commented Nov 11, 2020

    PR for the fix is created: #23237

    @vstinner
    Copy link
    Member

    @vstinner vstinner commented Nov 11, 2020

    commit cda99b4 (HEAD -> master, upstream/master)
    Author: Andrew Svetlov <andrew.svetlov@gmail.com>
    Date: Wed Nov 11 17:48:53 2020 +0200

    Fix memory leak introduced by python/cpython#66969 (GH-23237)
    

    @vstinner
    Copy link
    Member

    @vstinner vstinner commented Nov 11, 2020

    Thanks! The change fixed the leak:

    $ ./python -m test -j0 -R 3:3 test_asyncgen test_coroutines test_unittest # test_asyncio 
    (...)
    Tests result: SUCCESS

    I didn't run test_asyncio because the test is too slow.

    @asvetlov
    Copy link
    Contributor

    @asvetlov asvetlov commented Nov 11, 2020

    Thank you Victor for the report!

    @miss-islington
    Copy link
    Contributor

    @miss-islington miss-islington commented Nov 18, 2020

    New changeset 7c9487d by Vladimir Matveev in branch 'master':
    bpo-42085: Add documentation for Py_TPFLAGS_HAVE_AM_SEND (GH-23374)
    7c9487d

    @asvetlov
    Copy link
    Contributor

    @asvetlov asvetlov commented Nov 18, 2020

    Is anything left to do?

    @1st1
    Copy link
    Member

    @1st1 1st1 commented Nov 18, 2020

    Is anything left to do?

    I think we can close this now.

    @1st1 1st1 closed this Nov 18, 2020
    @1st1 1st1 closed this Nov 18, 2020
    @iritkatriel
    Copy link
    Member

    @iritkatriel iritkatriel commented May 29, 2021

    New changeset 0b11c42 by Martmists in branch 'main':
    bpo-42085: [docs] Add versionadded for am_send in type object documentation (GH-25465)
    0b11c42

    @iritkatriel
    Copy link
    Member

    @iritkatriel iritkatriel commented May 29, 2021

    New changeset d338ce0 by Miss Islington (bot) in branch '3.10':
    bpo-42085: [docs] Add versionadded for am_send in type object documentation (GH-25465) (GH-26453)
    d338ce0

    @encukou
    Copy link
    Member

    @encukou encukou commented Jul 20, 2021

    Py_TPFLAGS_HAVE_AM_SEND is unnecessary and I'd like to remove it.

    It is not possible for type objects to have a different layout than the interpreter:

    • extensions using the regular ABI must be recompiled for each feature version of Python
    • extensions using the stable ABI can only create types dynamically

    Or is there a different reason for Py_TPFLAGS_HAVE_AM_SEND? Checking it may be faster than ((Py_TYPE(x)->tp_as_async != NULL) && (Py_TYPE(x)->tp_as_async->am_send != NULL)), but I don't think the speedup is relevant.

    See bpo-42747

    @sweeneyde
    Copy link
    Member

    @sweeneyde sweeneyde commented Aug 21, 2021

    Is there documentation anywhere for the semantics of am_send? I only see the signature followed by "See PyIter_Send for details", but the doc for PyIter_Send doesn't mention am_send.

    In particular, it would be nice to document the relationship between PyIter_Send, am_send, and tp_iternext.

    @pablogsal
    Copy link
    Member

    @pablogsal pablogsal commented Aug 25, 2021

    I am reopening this issue since am_send never got documented here: https://docs.python.org/3/c-api/typeobj.html#async-structs

    @pablogsal pablogsal reopened this Aug 25, 2021
    @pablogsal pablogsal reopened this Aug 25, 2021
    @sweeneyde
    Copy link
    Member

    @sweeneyde sweeneyde commented Aug 26, 2021

    It did get added to the correct docs:

    https://docs.python.org/3.10/c-api/typeobj.html#c.PyAsyncMethods.am_send

    (the 3.10 and 3.11 docs, not the 3.9 docs ;-)

    But as I mentioned, I feel that there could be more details about the semantics/contract.

    @pablogsal
    Copy link
    Member

    @pablogsal pablogsal commented Aug 26, 2021

    Oh, my bad. I can't find the enum values of the return type, though (PySendResult).

    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    3.10 interpreter-core performance
    Projects
    None yet
    Development

    No branches or pull requests

    8 participants
    X Tutup