This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: using concurrent.futures.ProcessPoolExecutor in class giving 'TypeError: can't pickle _thread.RLock objects' in 3.6, but not 3.5
Type: behavior Stage: resolved
Components: Library (Lib) Versions: Python 3.6
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: josh.r, r.david.murray, serhiy.storchaka, spencera, terry.reedy
Priority: normal Keywords:

Created on 2017-02-02 21:00 by spencera, last changed 2022-04-11 14:58 by admin. This issue is now closed.

Files
File name Uploaded Description Edit
test.py spencera, 2017-02-02 21:00 example code
Messages (9)
msg286825 - (view) Author: (spencera) Date: 2017-02-02 21:00
I'm unable to use concurrent.futures.ProcessPoolExecutor within a class in 3.6 the way I can in 3.5.x. I get the following in 3.6 (python3.6 test.py):

Traceback (most recent call last):
  File "/usr/local/lib/python3.6/multiprocessing/queues.py", line 241, in _feed
    obj = _ForkingPickler.dumps(obj)
  File "/usr/local/lib/python3.6/multiprocessing/reduction.py", line 51, in dumps
    cls(buf, protocol).dump(obj)
TypeError: can't pickle _thread.RLock objects

---------------------

No issues in 3.5.x:
0
1
2
3
4
5
6
7
8
9
0
...
msg286830 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2017-02-02 21:39
The fact that RLock's *appeared* to be picklable was a bug in previous versions of python (see issue 22995).

If you had code that worked before actually using the locks then perhaps there is a deeper error, though, so I'm nosying Serhiy to take a look at this (I don't use concurrent.futures so I'm not qualified to evaluate your example for validity).
msg286831 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2017-02-02 22:31
Oops, didn't mean to assign this to terry :(
msg286841 - (view) Author: Josh Rosenberg (josh.r) * (Python triager) Date: 2017-02-03 04:14
Looks like the problem here is that pickling self._consume implicitly pickles self, and after the first submission, self._futures contains Future objects. Those are probably what have the RLock in them (to synchronize between reading and populating threads), and it's correct not to pickle them; they're only meaningful in the parent process, and sending them to the workers would break, badly.

Given you don't seem to be using self for anything, you could either make _consume a staticmethod (if you need state from self, pass that specific state in as arguments) so it's not implicitly pickling and transmitting self, or failing that, define custom pickling functions that explicitly exclude self._futures from the set of attributes to pickle.

There is nothing to fix behaviorally on Python's side that wouldn't lead to confusion/breakage in other code. It would be nice if Python could give more detail on pickle chain that led to the unpicklable object (so you know it's self._consume->self->self._futures->some future object->future._rlock or whatever), but I'm not sure the pickling protocol design can preserve that sort of chain for error reporting...
msg286844 - (view) Author: (spencera) Date: 2017-02-03 06:25
Interesting. So, out of curiosity, what has changed from 3.5.2 to 3.6.0 that causes this new behavior? Was an instance associated with an instance method that was passed to submit not implicitly pickled before 3.6.0? Is it from the changes to the pickle module in 3.6? Something else?
msg286865 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2017-02-03 13:41
See the issue I linked to.  RLocks were incorrectly pickled before but the resulting unpickled object was broken.  If the unpickled RLock never got used such code would not break, but the objects were inherently broken and this could lead to hard to debug problem when the objects were used.  Thus we fixed it in 3.6 only so as to not break working code in a maintenance release.  But in 3.6 and later, RLocks (among other things that were also broken) are no longer pickleable.
msg286866 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2017-02-03 13:46
Oh, I take it back, it looks like the change was backported.  I think that's bad, but I wasn't involved in the decision :(
msg286868 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2017-02-03 14:09
It was backported but later reverted (54dd5c105334).

I concur with Josh. Thank you for good analysis Josh.

As for your idea about more detailed error reporting, I think it can be 
implemented. Separate exception can be raised for every object in the chain, 
with chaining one exception to other. This is separate issue.
msg286875 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2017-02-03 15:59
Josh> There is nothing to fix behaviorally on Python's side ...
Serhiy> I concur with Josh....

This implies to me that we should close this as 'not a bug', with possibly a new issue for better error reporting.
History
Date User Action Args
2022-04-11 14:58:42adminsetgithub: 73609
2017-02-03 16:04:24serhiy.storchakasetstatus: open -> closed
resolution: not a bug
stage: resolved
2017-02-03 15:59:13terry.reedysetmessages: + msg286875
2017-02-03 14:09:32serhiy.storchakasetmessages: + msg286868
2017-02-03 13:46:25r.david.murraysetmessages: + msg286866
2017-02-03 13:41:39r.david.murraysetmessages: + msg286865
2017-02-03 06:25:12spencerasetmessages: + msg286844
2017-02-03 04:14:43josh.rsetnosy: + josh.r
messages: + msg286841
2017-02-02 22:31:34r.david.murraysetassignee: terry.reedy ->
messages: + msg286831
2017-02-02 21:39:39r.david.murraysetassignee: terry.reedy

messages: + msg286830
nosy: + r.david.murray, terry.reedy, serhiy.storchaka
2017-02-02 21:00:20spenceracreate