Skip to content

Commit 27df1dc

Browse files
itamarofacebook-github-bot
authored andcommitted
Backport gh-100345 / Port D39555934: Provide C implementation for asyncio.current_task
Summary: Implementing it in C makes it about 4x-6x faster Upstream issue: python/cpython#100344 Upstream PR (3.12): python/cpython#100345 Original summary from D39555934 (ef8c620): Provide a native implementation of current_task as it is called frequently in the RequestContext scope guards. Reviewed By: alexmalyshev Differential Revision: D42229719 fbshipit-source-id: 9c3de43
1 parent 6bfcbed commit 27df1dc

File tree

4 files changed

+93
-8
lines changed

4 files changed

+93
-8
lines changed

Lib/asyncio/tasks.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -971,12 +971,14 @@ def _unregister_task(task):
971971
_py_enter_task = _enter_task
972972
_py_leave_task = _leave_task
973973
_py_all_tasks = all_tasks
974+
_py_current_task = current_task
974975

975976
try:
976977
from _asyncio import (_register_task, _unregister_task,
977978
_enter_task, _leave_task,
978979
_current_tasks,
979980
all_tasks,
981+
current_task,
980982
AsyncLazyValue as _ASYNC_LAZY_VALUE_TYPE,
981983
gather,
982984
_is_coro_suspended,
@@ -989,3 +991,4 @@ def _unregister_task(task):
989991
_c_enter_task = _enter_task
990992
_c_leave_task = _leave_task
991993
_c_all_tasks = all_tasks
994+
_c_current_task = current_task

Lib/test/test_asyncio/test_tasks.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2972,6 +2972,7 @@ class CIntrospectionTests(test_utils.TestCase, BaseTaskIntrospectionTests):
29722972

29732973

29742974
class BaseCurrentLoopTests:
2975+
current_task = None
29752976

29762977
def setUp(self):
29772978
super().setUp()
@@ -2982,33 +2983,39 @@ def new_task(self, coro):
29822983
raise NotImplementedError
29832984

29842985
def test_current_task_no_running_loop(self):
2985-
self.assertIsNone(asyncio.current_task(loop=self.loop))
2986+
self.assertIsNone(self.current_task(loop=self.loop))
29862987

29872988
def test_current_task_no_running_loop_implicit(self):
29882989
with self.assertRaises(RuntimeError):
2989-
asyncio.current_task()
2990+
self.current_task()
29902991

29912992
def test_current_task_with_implicit_loop(self):
29922993
async def coro():
2993-
self.assertIs(asyncio.current_task(loop=self.loop), task)
2994+
self.assertIs(self.current_task(loop=self.loop), task)
29942995

2995-
self.assertIs(asyncio.current_task(None), task)
2996-
self.assertIs(asyncio.current_task(), task)
2996+
self.assertIs(self.current_task(None), task)
2997+
self.assertIs(self.current_task(), task)
29972998

29982999
task = self.new_task(coro())
29993000
self.loop.run_until_complete(task)
3000-
self.assertIsNone(asyncio.current_task(loop=self.loop))
3001+
self.assertIsNone(self.current_task(loop=self.loop))
30013002

30023003

30033004
class PyCurrentLoopTests(BaseCurrentLoopTests, test_utils.TestCase):
3005+
current_task = staticmethod(tasks._py_current_task)
30043006

30053007
def new_task(self, coro):
30063008
return tasks._PyTask(coro, loop=self.loop)
30073009

30083010

3009-
@unittest.skipUnless(hasattr(tasks, '_CTask'),
3011+
@unittest.skipUnless(hasattr(tasks, '_CTask') and
3012+
hasattr(tasks, '_c_current_task'),
30103013
'requires the C _asyncio module')
30113014
class CCurrentLoopTests(BaseCurrentLoopTests, test_utils.TestCase):
3015+
if hasattr(tasks, '_c_current_task'):
3016+
current_task = staticmethod(tasks._c_current_task)
3017+
else:
3018+
current_task = None
30123019

30133020
def new_task(self, coro):
30143021
return getattr(tasks, '_CTask')(coro, loop=self.loop)

Modules/_asynciomodule.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8344,6 +8344,43 @@ static PyTypeObject _AwaitingFuture_Type = {
83448344
};
83458345

83468346

8347+
/*[clinic input]
8348+
_asyncio.current_task
8349+
8350+
loop: object = None
8351+
8352+
Return a currently executed task.
8353+
8354+
[clinic start generated code]*/
8355+
8356+
static PyObject *
8357+
_asyncio_current_task_impl(PyObject *module, PyObject *loop)
8358+
/*[clinic end generated code: output=fe15ac331a7f981a input=58910f61a5627112]*/
8359+
{
8360+
PyObject *ret;
8361+
8362+
if (loop == Py_None) {
8363+
loop = _asyncio_get_running_loop_impl(module);
8364+
if (loop == NULL) {
8365+
return NULL;
8366+
}
8367+
} else {
8368+
Py_INCREF(loop);
8369+
}
8370+
8371+
ret = PyDict_GetItemWithError(current_tasks, loop);
8372+
Py_DECREF(loop);
8373+
if (ret == NULL && PyErr_Occurred()) {
8374+
return NULL;
8375+
}
8376+
else if (ret == NULL) {
8377+
Py_RETURN_NONE;
8378+
}
8379+
Py_INCREF(ret);
8380+
return ret;
8381+
}
8382+
8383+
83478384
/*********************** Module **************************/
83488385

83498386

@@ -8534,6 +8571,7 @@ module_init(void)
85348571
PyDoc_STRVAR(module_doc, "Accelerator module for asyncio");
85358572

85368573
static PyMethodDef asyncio_methods[] = {
8574+
_ASYNCIO_CURRENT_TASK_METHODDEF
85378575
_ASYNCIO_GET_EVENT_LOOP_METHODDEF
85388576
_ASYNCIO__GET_EVENT_LOOP_METHODDEF
85398577
_ASYNCIO_GET_RUNNING_LOOP_METHODDEF

Modules/clinic/_asynciomodule.c.h

Lines changed: 38 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)