Closed kenfar closed 7 years ago
Honestly, dealing with threaded code is annoying.
I added an extra statement before calling widget_inspector and the error is fixed!
I feel like I understand nothing right now.
@enforce.runtime_validation
def test_one_widget(widget_id: int) -> int:
print('ID:', widget_id)
score = widget_inspector(widget_id, a='foo', b=4, c='bar')
return score
Any ideas? I am personally not very good at threaded usage of python.
UPDATE: It fails in debug though.
UPDATE2:
I think I found a quick fix for your problem using RLock. Please give it a try (dev branch) and tell me if you experience any problems with it. Thanks!
The sample code I provided is highlighting that it behaves somewhat randomly - where you can't really be sure exactly when & where it'll break and adding a line of code may alter the pattern a bit.
But I've got a ton of code I can run this through this weekend, and will let you know.
Yes, please try the dev branch out. The CI running the snippet you posted here now succeeds.
Yep, that seems to work fine - even when pushed hard with a ton of threads.
On a separate note - it fails with multiprocessing. To test it for multiprocessing all you need to do is replace this line: with concurrent.futures.ThreadPoolExecutor(max_workers=WORKERS) as executor: with this line: with concurrent.futures.ProcessPoolExecutor(max_workers=WORKERS) as executor:
However, I'd consider the multiprocessing issue to be separate, and it's still a success to work with threading even if multiprocessing doesn't work.
I am unconvinced that this is a problem on our end.
Dig into the SO page here: https://stackoverflow.com/questions/9336646/python-decorator-with-multiprocessing-fails
TL;DR ProcessPools can only accept pickleable things to spawn into processes. Decorated functions are inherently not pickleable, since it's a function wrapper and not an actual function.
A semi-reasonable solution is as follows:
def test_one_widget(widget_id: int) -> int:
@enforce.runtime_validation
def foo(widget_id: int) -> int:
score = widget_inspector(widget_id, a='foo', b=4, c='bar')
return score
return foo(widget_id)
Yep, on looking more closely this is definitely a general multiprocessing issue with using a decorator on the initial reference.
By the way, if everyone is happy with the current state of dev branch, I will upload an updated version of enforce to PyPi this weekend.
Closing this issue and opening a separate one for multiprocessing.
I'm running into odd issues with threading in which it appears that arguements and results are being replaced with None.
It runs fine with enforce with a single worker, and runs with with multiple workers and enforce disabled. But consistently breaks with multiple workers and enforce enabled.
Here's the code:
Test results with 1 worker or multiple workers but enforce off:
Test results with multiple workers and enforce on:
The results show failures in various areas running the same code. Sometimes caught by enforce, othertimes caught by assertions.