-
-
Notifications
You must be signed in to change notification settings - Fork 31.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
bpo-33521: Add 1.32x faster C implementation of asyncio.isfuture(). #6876
Conversation
Modules/_asynciomodule.c
Outdated
_Py_IDENTIFIER(__class__); | ||
PyObject* class = _PyObject_GetAttrId(obj, &PyId___class__); | ||
if (class == NULL) { | ||
return NULL; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use 4 spaces to ident your code (as the rest of _asynciomodule.c
file).
Modules/_asynciomodule.c
Outdated
_Py_IDENTIFIER(_asyncio_future_blocking); | ||
int class_has_attr = _PyObject_HasAttrId( | ||
class, &PyId__asyncio_future_blocking | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move );
to the previous line, so that
int class_has_attr = _PyObject_HasAttrId(
class, &PyId__asyncio_future_blocking);
Modules/_asynciomodule.c
Outdated
return NULL; | ||
} | ||
Py_DECREF(obj_attr); | ||
if (obj_attr != Py_None) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While this code is OK, you shouldn't use refs to Python objects after you DECREF them, it's a bad style. Please compare first, and decref after,
A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated. Once you have made the requested changes, please leave a comment on this pull request containing the phrase |
c72d089
to
58ad925
Compare
I have made the requested changes; please review again. |
Thanks for making the requested changes! @1st1: please review the changes made to this pull request. |
_asyncio_isfuture_impl(PyObject *module, PyObject *obj) | ||
/*[clinic end generated code: output=7ceb4ecaca613a86 input=b417c209efff25ec]*/ | ||
{ | ||
_Py_IDENTIFIER(__class__); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not use Future_CheckExact()
/ Future_Check()
as very fast happy path here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@asvetlov @1st1 isfuture check if _asyncio_future_blocking exists and is not None because mock object has _asyncio_future_blocking as None and we want to return isfuture() as False in this case.
See test case
cpython/Lib/test/test_asyncio/test_futures.py
Lines 123 to 124 in 8425de4
# As `isinstance(Mock(), Future)` returns `False` | |
self.assertFalse(asyncio.isfuture(mock.Mock())) |
Do we really want to use Future_CheckExact to return fast?
A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated. Once you have made the requested changes, please leave a comment on this pull request containing the phrase |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know whether it is worth to add C implementation of this function, but I think it can be simplified.
See also that the _asyncio_future_blocking
attribute is used in the existing C code in suboptimal way.
/*[clinic end generated code: output=7ceb4ecaca613a86 input=b417c209efff25ec]*/ | ||
{ | ||
_Py_IDENTIFIER(__class__); | ||
PyObject* class = _PyObject_GetAttrId(obj, &PyId___class__); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is better to use Py_TYPE()
for convenience and speed . There is a subtle difference between the type and the __class__
attribute, but it is usually ignored when write C accelerations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggested to @jimmylai to get the class attribute to make sure that the C implementation behaves as the Python implementation: see PEP 399. If someone wants to use type(), I would prefer to see the same change in the Python implementation as well.
@1st1, @asvetlov: Do you know the rationale for checking class here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggested to use Py_TYPE
as well.
I think it was I who used __class__
there, and there's no rationale behind that :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So the Python version can be updated to use type()
too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@1st1 @serhiy-storchaka
use type() won't work.
Original isfuture: return (hasattr(obj.__class__, '_asyncio_future_blocking') and obj._asyncio_future_blocking is not None)
Use type: return (hasattr(type(obj), '_asyncio_future_blocking') and obj._asyncio_future_blocking is not None)
Unit tests fail when use type()
Did I use type() wrong?
======================================================================
FAIL: test_isfuture (test.test_asyncio.test_futures.CFutureTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/jimmylai/workspace/cpython/Lib/test/test_asyncio/test_futures.py", line 131, in test_isfuture
self.assertTrue(asyncio.isfuture(mock.Mock(type(f))))
AssertionError: False is not true
======================================================================
FAIL: test_isfuture (test.test_asyncio.test_futures.CSubFutureTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/jimmylai/workspace/cpython/Lib/test/test_asyncio/test_futures.py", line 131, in test_isfuture
self.assertTrue(asyncio.isfuture(mock.Mock(type(f))))
AssertionError: False is not true
======================================================================
FAIL: test_isfuture (test.test_asyncio.test_futures.PyFutureTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/jimmylai/workspace/cpython/Lib/test/test_asyncio/test_futures.py", line 131, in test_isfuture
self.assertTrue(asyncio.isfuture(mock.Mock(type(f))))
AssertionError: False is not true
Modules/_asynciomodule.c
Outdated
} | ||
PyObject* obj_attr = _PyObject_GetAttrId(obj, &PyId__asyncio_future_blocking); | ||
if (obj_attr == NULL) { | ||
return NULL; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use 4-space indentation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed.
/*[clinic input] | ||
_asyncio.isfuture | ||
|
||
obj: object |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make the argument positional-only.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In pratice, it means adding "/" on a new line, aligned with "obj", and run "make clinic" again.
return NULL; | ||
} | ||
_Py_IDENTIFIER(_asyncio_future_blocking); | ||
int class_has_attr = _PyObject_HasAttrId( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
class may not have attr _asyncio_future_blocking
It's needed.
Py_DECREF(obj_attr); | ||
Py_RETURN_TRUE; | ||
} | ||
Py_RETURN_FALSE; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
obj_attr is leaked here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added Py_DECREF(obj_attr);
55c77d7
to
66e4586
Compare
66e4586
to
d689d5f
Compare
I have made the requested changes; please review again. |
@jimmylai the PR is failing on tests passing. |
@jimmylai, please take a look at the last comment and please also resolve the merge conflict. Thank you! |
This PR is awaiting changes for over two years, tests were failing and has merge conflicts so I am closing it. If you are still interested you can create a new PR with the requested changes or this one can be reopened if needed. |
https://bugs.python.org/issue33521