This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Add dedicated slot for sending values
Type: performance Stage: resolved
Components: Interpreter Core Versions: Python 3.10
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: Dennis Sweeney, asvetlov, iritkatriel, martmists, miss-islington, pablogsal, petr.viktorin, v2m, yselivanov
Priority: normal Keywords: patch

Created on 2020-10-19 19:38 by v2m, last changed 2022-04-11 14:59 by admin.

Pull Requests
URL Status Linked Edit
PR 22780 merged v2m, 2020-10-19 19:39
PR 23237 merged asvetlov, 2020-11-11 15:02
PR 23374 merged v2m, 2020-11-18 18:41
PR 25465 merged martmists, 2021-05-29 20:23
PR 26453 merged miss-islington, 2021-05-29 20:30
Messages (19)
msg378999 - (view) Author: Vladimir Matveev (v2m) * Date: 2020-10-19 19:38
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
msg380706 - (view) Author: Yury Selivanov (yselivanov) * (Python committer) Date: 2020-11-10 20:10
New changeset 1e996c3a3b51e9c6f1f4cea8a6dbcf3bcb865060 by Vladimir Matveev in branch 'master':
bpo-42085: Introduce dedicated entry in PyAsyncMethods for sending values (#22780)
https://github.com/python/cpython/commit/1e996c3a3b51e9c6f1f4cea8a6dbcf3bcb865060
msg380708 - (view) Author: Yury Selivanov (yselivanov) * (Python committer) Date: 2020-11-10 20:10
Vladimir, please do a follow up PR documenting Py_TPFLAGS_HAVE_AM_SEND.
msg380750 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2020-11-11 11:22
> New changeset 1e996c3a3b51e9c6f1f4cea8a6dbcf3bcb865060 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
msg380763 - (view) Author: Andrew Svetlov (asvetlov) * (Python committer) Date: 2020-11-11 14:07
Investigating. The test leaks a future instance.
msg380765 - (view) Author: Andrew Svetlov (asvetlov) * (Python committer) Date: 2020-11-11 15:07
PR for the fix is created: https://github.com/python/cpython/pull/23237
msg380770 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2020-11-11 16:46
commit cda99b4022daa08ac74b0420e9903cce883d91c6 (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 GH-22780 (GH-23237)
msg380772 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2020-11-11 16:50
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.
msg380777 - (view) Author: Andrew Svetlov (asvetlov) * (Python committer) Date: 2020-11-11 17:20
Thank you Victor for the report!
msg381369 - (view) Author: miss-islington (miss-islington) Date: 2020-11-18 18:58
New changeset 7c9487ded487f304c2906698c52f0815b92cbeb6 by Vladimir Matveev in branch 'master':
bpo-42085: Add documentation for Py_TPFLAGS_HAVE_AM_SEND (GH-23374)
https://github.com/python/cpython/commit/7c9487ded487f304c2906698c52f0815b92cbeb6
msg381375 - (view) Author: Andrew Svetlov (asvetlov) * (Python committer) Date: 2020-11-18 22:08
Is anything left to do?
msg381381 - (view) Author: Yury Selivanov (yselivanov) * (Python committer) Date: 2020-11-18 23:39
> Is anything left to do?

I think we can close this now.
msg394736 - (view) Author: Irit Katriel (iritkatriel) * (Python committer) Date: 2021-05-29 20:30
New changeset 0b11c429c7f1721d9ffb9ae19e3e8e2e7bd6444d by Martmists in branch 'main':
bpo-42085: [docs] Add versionadded for am_send in type object documentation (GH-25465)
https://github.com/python/cpython/commit/0b11c429c7f1721d9ffb9ae19e3e8e2e7bd6444d
msg394737 - (view) Author: Irit Katriel (iritkatriel) * (Python committer) Date: 2021-05-29 20:38
New changeset d338ce0796e5fe8e54dfe52f93ed9d5936ad3efe by Miss Islington (bot) in branch '3.10':
bpo-42085: [docs] Add versionadded for am_send in type object documentation (GH-25465) (GH-26453)
https://github.com/python/cpython/commit/d338ce0796e5fe8e54dfe52f93ed9d5936ad3efe
msg397872 - (view) Author: Petr Viktorin (petr.viktorin) * (Python committer) Date: 2021-07-20 14:09
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
msg400045 - (view) Author: Dennis Sweeney (Dennis Sweeney) * (Python committer) Date: 2021-08-21 22:29
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.
msg400299 - (view) Author: Pablo Galindo Salgado (pablogsal) * (Python committer) Date: 2021-08-25 21:41
I am reopening this issue since am_send never got documented here: https://docs.python.org/3/c-api/typeobj.html#async-structs
msg400310 - (view) Author: Dennis Sweeney (Dennis Sweeney) * (Python committer) Date: 2021-08-26 05:31
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.
msg400330 - (view) Author: Pablo Galindo Salgado (pablogsal) * (Python committer) Date: 2021-08-26 09:51
Oh, my bad. I can't find the enum values of the return type, though (PySendResult).
History
Date User Action Args
2022-04-11 14:59:37adminsetgithub: 86251
2021-08-26 09:51:38pablogsalsetmessages: + msg400330
2021-08-26 05:31:26Dennis Sweeneysetmessages: + msg400310
2021-08-25 21:41:30pablogsalsetstatus: closed -> open

nosy: + pablogsal
messages: + msg400299

resolution: fixed ->
2021-08-21 22:29:25Dennis Sweeneysetnosy: + Dennis Sweeney
messages: + msg400045
2021-07-20 14:09:33petr.viktorinsetnosy: + petr.viktorin
messages: + msg397872
2021-05-29 20:38:04iritkatrielsetmessages: + msg394737
2021-05-29 20:30:39miss-islingtonsetpull_requests: + pull_request25049
2021-05-29 20:30:35iritkatrielsetnosy: + iritkatriel
messages: + msg394736
2021-05-29 20:23:50martmistssetnosy: + martmists

pull_requests: + pull_request25048
2020-11-18 23:39:19yselivanovsetstatus: open -> closed
resolution: fixed
stage: patch review -> resolved
2020-11-18 23:39:10yselivanovsetmessages: + msg381381
2020-11-18 22:08:09asvetlovsetmessages: + msg381375
2020-11-18 21:38:05vstinnersetnosy: - vstinner
2020-11-18 18:58:46miss-islingtonsetnosy: + miss-islington
messages: + msg381369
2020-11-18 18:41:18v2msetpull_requests: + pull_request22267
2020-11-11 17:20:30asvetlovsetmessages: + msg380777
2020-11-11 16:50:35vstinnersetmessages: + msg380772
2020-11-11 16:46:56vstinnersetmessages: + msg380770
2020-11-11 15:07:38asvetlovsetmessages: + msg380765
2020-11-11 15:02:07asvetlovsetpull_requests: + pull_request22135
2020-11-11 14:07:59asvetlovsetmessages: + msg380763
2020-11-11 11:22:15vstinnersetnosy: + vstinner
messages: + msg380750
2020-11-10 20:10:52yselivanovsetmessages: + msg380708
2020-11-10 20:10:03yselivanovsetmessages: + msg380706
2020-10-21 03:23:56terry.reedysetnosy: + asvetlov, yselivanov
2020-10-20 18:04:19v2msettype: performance
2020-10-19 19:39:12v2msetkeywords: + patch
stage: patch review
pull_requests: + pull_request21739
2020-10-19 19:38:16v2mcreate