Skip to content

Commit 4cc63e0

Browse files
authored
gh-100344: Add C implementation for asyncio.current_task (#100345)
Co-authored-by: pranavtbhat
1 parent aa878f0 commit 4cc63e0

File tree

6 files changed

+123
-9
lines changed

6 files changed

+123
-9
lines changed

Doc/whatsnew/3.12.rst

+3
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,9 @@ asyncio
225225
a custom event loop factory.
226226
(Contributed by Kumar Aditya in :gh:`99388`.)
227227

228+
* Add C implementation of :func:`asyncio.current_task` for 4x-6x speedup.
229+
(Contributed by Itamar Ostricher and Pranav Thulasiram Bhat in :gh:`100344`.)
230+
228231
inspect
229232
-------
230233

Lib/asyncio/tasks.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -964,6 +964,7 @@ def _unregister_task(task):
964964
_all_tasks.discard(task)
965965

966966

967+
_py_current_task = current_task
967968
_py_register_task = _register_task
968969
_py_unregister_task = _unregister_task
969970
_py_enter_task = _enter_task
@@ -973,10 +974,12 @@ def _unregister_task(task):
973974
try:
974975
from _asyncio import (_register_task, _unregister_task,
975976
_enter_task, _leave_task,
976-
_all_tasks, _current_tasks)
977+
_all_tasks, _current_tasks,
978+
current_task)
977979
except ImportError:
978980
pass
979981
else:
982+
_c_current_task = current_task
980983
_c_register_task = _register_task
981984
_c_unregister_task = _unregister_task
982985
_c_enter_task = _enter_task

Lib/test/test_asyncio/test_tasks.py

+14-7
Original file line numberDiff line numberDiff line change
@@ -2804,6 +2804,7 @@ class CIntrospectionTests(test_utils.TestCase, BaseTaskIntrospectionTests):
28042804

28052805

28062806
class BaseCurrentLoopTests:
2807+
current_task = None
28072808

28082809
def setUp(self):
28092810
super().setUp()
@@ -2814,33 +2815,39 @@ def new_task(self, coro):
28142815
raise NotImplementedError
28152816

28162817
def test_current_task_no_running_loop(self):
2817-
self.assertIsNone(asyncio.current_task(loop=self.loop))
2818+
self.assertIsNone(self.current_task(loop=self.loop))
28182819

28192820
def test_current_task_no_running_loop_implicit(self):
28202821
with self.assertRaisesRegex(RuntimeError, 'no running event loop'):
2821-
asyncio.current_task()
2822+
self.current_task()
28222823

28232824
def test_current_task_with_implicit_loop(self):
28242825
async def coro():
2825-
self.assertIs(asyncio.current_task(loop=self.loop), task)
2826+
self.assertIs(self.current_task(loop=self.loop), task)
28262827

2827-
self.assertIs(asyncio.current_task(None), task)
2828-
self.assertIs(asyncio.current_task(), task)
2828+
self.assertIs(self.current_task(None), task)
2829+
self.assertIs(self.current_task(), task)
28292830

28302831
task = self.new_task(coro())
28312832
self.loop.run_until_complete(task)
2832-
self.assertIsNone(asyncio.current_task(loop=self.loop))
2833+
self.assertIsNone(self.current_task(loop=self.loop))
28332834

28342835

28352836
class PyCurrentLoopTests(BaseCurrentLoopTests, test_utils.TestCase):
2837+
current_task = staticmethod(tasks._py_current_task)
28362838

28372839
def new_task(self, coro):
28382840
return tasks._PyTask(coro, loop=self.loop)
28392841

28402842

2841-
@unittest.skipUnless(hasattr(tasks, '_CTask'),
2843+
@unittest.skipUnless(hasattr(tasks, '_CTask') and
2844+
hasattr(tasks, '_c_current_task'),
28422845
'requires the C _asyncio module')
28432846
class CCurrentLoopTests(BaseCurrentLoopTests, test_utils.TestCase):
2847+
if hasattr(tasks, '_c_current_task'):
2848+
current_task = staticmethod(tasks._c_current_task)
2849+
else:
2850+
current_task = None
28442851

28452852
def new_task(self, coro):
28462853
return getattr(tasks, '_CTask')(coro, loop=self.loop)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Provide C implementation for :func:`asyncio.current_task` for a 4x-6x
2+
speedup.

Modules/_asynciomodule.c

+39
Original file line numberDiff line numberDiff line change
@@ -3314,6 +3314,44 @@ _asyncio__leave_task_impl(PyObject *module, PyObject *loop, PyObject *task)
33143314
}
33153315

33163316

3317+
/*[clinic input]
3318+
_asyncio.current_task
3319+
3320+
loop: object = None
3321+
3322+
Return a currently executed task.
3323+
3324+
[clinic start generated code]*/
3325+
3326+
static PyObject *
3327+
_asyncio_current_task_impl(PyObject *module, PyObject *loop)
3328+
/*[clinic end generated code: output=fe15ac331a7f981a input=58910f61a5627112]*/
3329+
{
3330+
PyObject *ret;
3331+
asyncio_state *state = get_asyncio_state(module);
3332+
3333+
if (loop == Py_None) {
3334+
loop = _asyncio_get_running_loop_impl(module);
3335+
if (loop == NULL) {
3336+
return NULL;
3337+
}
3338+
} else {
3339+
Py_INCREF(loop);
3340+
}
3341+
3342+
ret = PyDict_GetItemWithError(state->current_tasks, loop);
3343+
Py_DECREF(loop);
3344+
if (ret == NULL && PyErr_Occurred()) {
3345+
return NULL;
3346+
}
3347+
else if (ret == NULL) {
3348+
Py_RETURN_NONE;
3349+
}
3350+
Py_INCREF(ret);
3351+
return ret;
3352+
}
3353+
3354+
33173355
/*********************** Module **************************/
33183356

33193357

@@ -3494,6 +3532,7 @@ module_init(asyncio_state *state)
34943532
PyDoc_STRVAR(module_doc, "Accelerator module for asyncio");
34953533

34963534
static PyMethodDef asyncio_methods[] = {
3535+
_ASYNCIO_CURRENT_TASK_METHODDEF
34973536
_ASYNCIO_GET_EVENT_LOOP_METHODDEF
34983537
_ASYNCIO_GET_RUNNING_LOOP_METHODDEF
34993538
_ASYNCIO__GET_RUNNING_LOOP_METHODDEF

Modules/clinic/_asynciomodule.c.h

+61-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)