-
-
Notifications
You must be signed in to change notification settings - Fork 31.4k
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-14976: Reentrant simple queue #3346
Conversation
e36a3c5
to
ee5b4cb
Compare
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.
When the docs are made, the reentrancy guarantee should be listed as a C-implementation detail.
Lib/queue.py
Outdated
@@ -8,16 +8,26 @@ | |||
from heapq import heappush, heappop | |||
from time import monotonic as time | |||
|
|||
try: |
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.
The usual way to incorporate the C extension is to put a "from _queue import SimpleQueue"
self = (simplequeueobject *) type->tp_alloc(type, 0); | ||
if (self != NULL) { | ||
self->weakreflist = NULL; | ||
self->lst = PyList_New(0); |
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.
Can you swap in a deque() using PyObject_Call?
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 would replace all the simple PyList
C API calls with more cumbersome method calls through the PyObject
API. Also, since generic method calls can allocate tuples, they might release the GIL (though I haven't checked for sure). Do you think it's worth it?
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.
Agreed. Go ahead and stick with the PyList calls.
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.
Approval for the Windows build files - they look fine.
@rhettinger, what should be the way forward here? Do you have further requests on this PR? |
@rhettinger could I have your feedback on this? |
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.
overall good, a couple comments to think about but nothing worth blocking this.
Lib/test/test_queue.py
Outdated
type2test = queue._PySimpleQueue | ||
|
||
|
||
if _queue is not 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.
rather than a big conditional indented class implementation, why not use @unittest.skipIf(_queue is None, 'No _queue module found')
on the class? (your load time type2test assignment can be made conditional or done at runtime in a setUp() method so it won't run when skipped)
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.
Sounds fair enough, will do.
class _PySimpleQueue: | ||
'''Simple, unbounded FIFO queue. | ||
|
||
This pure Python implementation is not reentrant. |
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.
What is the point of the pure python version existing at all of it's raison d'être isn't possible? Even on PyPy if they took this module and haven't implemented a _queue equivalent it would do the wrong thing for code that wants to use SimpleQueue for reentrant API reasons.
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 know its presence is debattable, but providing a pure Python version is current policy. Besides, being reentrant is documented as an implementation detail, not an intrinsic property of the API.
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.
The size of the internal list shouldn't be included in the result of __sizeof__
.
Modules/_queuemodule.c
Outdated
} | ||
|
||
/*[clinic input] | ||
_queue.SimpleQueue.empty |
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.
You can use the bool return converter.
_queue.SimpleQueue.empty -> bool
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.
Will do.
Modules/_queuemodule.c
Outdated
Py_ssize_t res; | ||
|
||
res = _PyObject_SIZE(Py_TYPE(self)); | ||
res += _PySys_GetSizeOf(self->lst); |
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.
Since the list is visited in tp_traverse, its size shouldn't be include in the result of __sizeof__
.
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.
Hmm... what does tp_traverse have to do with it?
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.
sys.getsizeof()
is a low-level tool that returns the only size of the object, without subobjects. A high-level tool will calls sys.getsizeof()
recursively for the tree of objects using gc.get_referents()
. gc.get_referents()
is build by using tp_traverse. If __sizeof__
includes the size of objects exposed in tp_traverse, it will be counted twice.
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.
That's a fair point, even though any non-trivial __sizeof__
defined in pure Python would have the same problem (see for example the pure-Python OrderedDict.__sizeof__
).
I'll make the change.
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.
OrderedDict.__sizeof__
is incorrect. In general pure Python classes shouldn't define __sizeof__
(as well as __basicsize__
or __dictoffset__
).
0, /*tp_iter*/ | ||
0, /*tp_iternext*/ | ||
simplequeue_methods, /*tp_methods*/ | ||
0, /* tp_members */ |
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.
Inconsistent use of spaces in comments.
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 will happily let others reformat if they're irritated by inconsistent spaces in comments.
Modules/_queuemodule.c
Outdated
} | ||
|
||
/*[clinic input] | ||
_queue.SimpleQueue.qsize |
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.
You cause the Py_ssize_t return converter.
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.
Will do.
Modules/_queuemodule.c
Outdated
} | ||
|
||
/*[clinic input] | ||
_queue.SimpleQueue.__init__ |
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 think this method is needed. Instead use Argument Clinic for the __new__
method.
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 there an example somewhere of using Argument Clinic for a __new__
method?
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.
For example tuple.__new__
or complex.__new__
.
When you're done making the requested changes, leave the comment: |
https://bugs.python.org/issue14976
TODO: