bpo-14976: Reentrant simple queue#3346
Conversation
e36a3c5 to
ee5b4cb
Compare
rhettinger
left a comment
There was a problem hiding this comment.
When the docs are made, the reentrancy guarantee should be listed as a C-implementation detail.
| from heapq import heappush, heappop | ||
| from time import monotonic as time | ||
|
|
||
| try: |
There was a problem hiding this comment.
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.
Can you swap in a deque() using PyObject_Call?
There was a problem hiding this comment.
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.
Agreed. Go ahead and stick with the PyList calls.
zooba
left a comment
There was a problem hiding this comment.
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? |
gpshead
left a comment
There was a problem hiding this comment.
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.
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.
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.
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.
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.
serhiy-storchaka
left a comment
There was a problem hiding this comment.
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.
You can use the bool return converter.
_queue.SimpleQueue.empty -> bool
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.
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.
Hmm... what does tp_traverse have to do with it?
There was a problem hiding this comment.
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.
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.
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.
Inconsistent use of spaces in comments.
There was a problem hiding this comment.
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.
You cause the Py_ssize_t return converter.
Modules/_queuemodule.c
Outdated
| } | ||
|
|
||
| /*[clinic input] | ||
| _queue.SimpleQueue.__init__ |
There was a problem hiding this comment.
I don't think this method is needed. Instead use Argument Clinic for the __new__ method.
There was a problem hiding this comment.
Is there an example somewhere of using Argument Clinic for a __new__ method?
There was a problem hiding this comment.
For example tuple.__new__ or complex.__new__.
|
When you're done making the requested changes, leave the comment: |
https://bugs.python.org/issue14976
TODO: