Skip to content
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

Closed
wants to merge 2 commits into from

Conversation

jimmylai
Copy link

@jimmylai jimmylai commented May 15, 2018

@jimmylai jimmylai requested review from 1st1 and asvetlov as code owners May 15, 2018 20:02
@jimmylai jimmylai changed the title Add 1.32x faster C implementation of asyncio.isfuture(). bpo-33521: Add 1.32x faster C implementation of asyncio.isfuture(). May 15, 2018
@vstinner vstinner self-requested a review May 17, 2018 06:57
_Py_IDENTIFIER(__class__);
PyObject* class = _PyObject_GetAttrId(obj, &PyId___class__);
if (class == NULL) {
return NULL;
Copy link
Member

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).

_Py_IDENTIFIER(_asyncio_future_blocking);
int class_has_attr = _PyObject_HasAttrId(
class, &PyId__asyncio_future_blocking
);
Copy link
Member

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);

return NULL;
}
Py_DECREF(obj_attr);
if (obj_attr != Py_None) {
Copy link
Member

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,

@bedevere-bot
Copy link

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 I have made the requested changes; please review again. I will then notify any core developers who have left a review that you're ready for them to take another look at this pull request.

@jimmylai jimmylai force-pushed the optimize_isfuture branch 2 times, most recently from c72d089 to 58ad925 Compare May 19, 2018 16:25
@jimmylai
Copy link
Author

I have made the requested changes; please review again.

@bedevere-bot
Copy link

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__);
Copy link
Contributor

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?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea.

Copy link
Author

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

# As `isinstance(Mock(), Future)` returns `False`
self.assertFalse(asyncio.isfuture(mock.Mock()))

Do we really want to use Future_CheckExact to return fast?

@bedevere-bot
Copy link

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 I have made the requested changes; please review again. I will then notify any core developers who have left a review that you're ready for them to take another look at this pull request.

Copy link
Member

@serhiy-storchaka serhiy-storchaka left a 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__);
Copy link
Member

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.

Copy link
Member

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?

Copy link
Member

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 :)

Copy link
Member

@1st1 1st1 May 22, 2018

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.

Copy link
Author

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

}
PyObject* obj_attr = _PyObject_GetAttrId(obj, &PyId__asyncio_future_blocking);
if (obj_attr == NULL) {
return NULL;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use 4-space indentation.

Copy link
Author

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
Copy link
Member

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.

Copy link
Member

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(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it needed?

Copy link
Author

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;
Copy link
Member

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.

Copy link
Author

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);

@jimmylai jimmylai force-pushed the optimize_isfuture branch 3 times, most recently from 55c77d7 to 66e4586 Compare June 18, 2018 13:59
@jimmylai jimmylai force-pushed the optimize_isfuture branch from 66e4586 to d689d5f Compare June 18, 2018 13:59
@jimmylai
Copy link
Author

I have made the requested changes; please review again.

@bedevere-bot
Copy link

Thanks for making the requested changes!

@asvetlov, @1st1: please review the changes made to this pull request.

@asvetlov
Copy link
Contributor

asvetlov commented Aug 2, 2018

@jimmylai the PR is failing on tests passing.
Could you take a look?

@csabella
Copy link
Contributor

@jimmylai, please take a look at the last comment and please also resolve the merge conflict. Thank you!

@AlexWaygood AlexWaygood added performance Performance or resource usage topic-asyncio labels Apr 11, 2022
@kumaraditya303
Copy link
Contributor

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants