diff options
author | Vladimir Matveev <vladima@fb.com> | 2020-09-19 01:38:38 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-09-19 01:38:38 (GMT) |
commit | 2b05361bf7cbbd76035206fd9befe87f37489f1e (patch) | |
tree | d29b4c3ab8e617ee8f5f5440db83a2bfa3050666 /Modules/_asynciomodule.c | |
parent | ec8a15b034124f3b58d1addda789fa4c20313006 (diff) | |
download | cpython-2b05361bf7cbbd76035206fd9befe87f37489f1e.zip cpython-2b05361bf7cbbd76035206fd9befe87f37489f1e.tar.gz cpython-2b05361bf7cbbd76035206fd9befe87f37489f1e.tar.bz2 |
bpo-41756: Introduce PyGen_Send C API (GH-22196)
The new API allows to efficiently send values into native generators
and coroutines avoiding use of StopIteration exceptions to signal
returns.
ceval loop now uses this method instead of the old "private"
_PyGen_Send C API. This translates to 1.6x increased performance
of 'await' calls in micro-benchmarks.
Aside from CPython core improvements, this new API will also allow
Cython to generate more efficient code, benefiting high-performance
IO libraries like uvloop.
Diffstat (limited to 'Modules/_asynciomodule.c')
-rw-r--r-- | Modules/_asynciomodule.c | 27 |
1 files changed, 22 insertions, 5 deletions
diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index 4a1c91e..2151f20 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -2621,6 +2621,20 @@ task_set_error_soon(TaskObj *task, PyObject *et, const char *format, ...) Py_RETURN_NONE; } +static inline int +gen_status_from_result(PyObject **result) +{ + if (*result != NULL) { + return PYGEN_NEXT; + } + if (_PyGen_FetchStopIterationValue(result) == 0) { + return PYGEN_RETURN; + } + + assert(PyErr_Occurred()); + return PYGEN_ERROR; +} + static PyObject * task_step_impl(TaskObj *task, PyObject *exc) { @@ -2679,26 +2693,29 @@ task_step_impl(TaskObj *task, PyObject *exc) return NULL; } + int gen_status = PYGEN_ERROR; if (exc == NULL) { if (PyGen_CheckExact(coro) || PyCoro_CheckExact(coro)) { - result = _PyGen_Send((PyGenObject*)coro, Py_None); + gen_status = PyGen_Send((PyGenObject*)coro, Py_None, &result); } else { result = _PyObject_CallMethodIdOneArg(coro, &PyId_send, Py_None); + gen_status = gen_status_from_result(&result); } } else { result = _PyObject_CallMethodIdOneArg(coro, &PyId_throw, exc); + gen_status = gen_status_from_result(&result); if (clear_exc) { /* We created 'exc' during this call */ Py_DECREF(exc); } } - if (result == NULL) { + if (gen_status == PYGEN_RETURN || gen_status == PYGEN_ERROR) { PyObject *et, *ev, *tb; - if (_PyGen_FetchStopIterationValue(&o) == 0) { + if (result != NULL) { /* The error is StopIteration and that means that the underlying coroutine has resolved */ @@ -2709,10 +2726,10 @@ task_step_impl(TaskObj *task, PyObject *exc) res = future_cancel((FutureObj*)task, task->task_cancel_msg); } else { - res = future_set_result((FutureObj*)task, o); + res = future_set_result((FutureObj*)task, result); } - Py_DECREF(o); + Py_DECREF(result); if (res == NULL) { return NULL; |