bpo-41756: Introduce _PyGen_SendNoStopIteration to provide alternative way to return results from coroutines by vladima · Pull Request #22196 · python/cpython
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
| } | ||
| else { | ||
| /* Async generators cannot return anything but None */ | ||
| assert(!PyAsyncGen_CheckExact(gen)); | ||
| _PyGen_SetStopIterationValue(result); | ||
| if (is_return_value) { |
| { | ||
| PyThreadState *tstate = _PyThreadState_GET(); | ||
| PyFrameObject *f = gen->gi_frame; | ||
| PyObject *result; | ||
|
|
| @@ -225,7 +224,7 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing) | |||
|
|
|||
| /* If the generator just returned (as opposed to yielding), signal | |||
| * that the generator is exhausted. */ | |||
| if (result && _PyFrameHasCompleted(f)) { | |||
| @@ -235,13 +234,19 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing) | |||
| /* Set exception if not called by gen_iternext() */ | |||
| PyErr_SetNone(PyExc_StopIteration); | |||
| } | |||
| Py_CLEAR(result); | |||
| } | ||
|
|
||
| PyObject * | ||
| _PyGen_SendNoStopIteration(PyGenObject *gen, PyObject *arg, int *is_return_value) |
| @@ -2695,10 +2696,13 @@ task_step_impl(TaskObj *task, PyObject *exc) | |||
| } | |||
| } | |||
|
|
|||
| if (result == NULL) { | |||
| if ((gen_status == PYGEN_RETURN) || result == NULL) { | |||
| if (PyGen_CheckExact(coro) || PyCoro_CheckExact(coro)) { | ||
| result = _PyGen_Send((PyGenObject*)coro, Py_None); | ||
| gen_status = _PyGen_Send_NameTBD((PyGenObject*)coro, Py_None, &result); |
| if (result != NULL) { | ||
| o = result; | ||
| } | ||
| if (o || (_PyGen_FetchStopIterationValue(&o) == 0)) { |
| *is_return_value = 1; | ||
| } | ||
| else { | ||
| /* Set exception if not called by gen_iternext() */ |
| #define PYGEN_ERROR -1 | ||
| #define PYGEN_NEXT 1 | ||
|
|
||
| PyAPI_FUNC(int) PyGen_Send(PyGenObject *, PyObject *, PyObject **); |
1st1 approved these changes Sep 16, 2020
1st1 approved these changes Sep 18, 2020
|
|
||
| .. c:function:: PySendResult PyGen_Send(PyGenObject *gen, PyObject *arg, PyObject **presult) | ||
|
|
||
| Sends the *arg* value into the generator *gen*. Returns: |
| @@ -15,6 +15,11 @@ than explicitly calling :c:func:`PyGen_New` or :c:func:`PyGen_NewWithQualName`. | |||
| The C structure used for generator objects. | |||
|
|
|||
|
|
|||
| .. c:type:: PySendResult | |||
|
|
|||
| The enum value used to represent different results of :c:func:`PyGen_Send` | |||
xzy3 pushed a commit to xzy3/cpython that referenced this pull request
Oct 18, 2020The 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.