Uh oh!
There was an error while loading. Please reload this page.
[SPARK-12717][PYTHON] Adding thread-safe broadcast pickle registry - #18695
[SPARK-12717][PYTHON] Adding thread-safe broadcast pickle registry#18695BryanCutler wants to merge 6 commits into
Conversation
SparkQA
commented
Jul 20, 2017
Test build #79809 has finished for PR 18695 at commit
|
BryanCutler
commented
Jul 20, 2017
| self._registry = set() | ||
| self._lock = lock | ||
| @property |
There was a problem hiding this comment.
Would you mind if i ask why this one should be a property?
There was a problem hiding this comment.
sure @HyukjinKwon, it's not really necessary. It's just there to basically say that the lock should not be changed once this class is instantiated, so to keep it "private" but allowed to be acquired. Maybe it's overkill here because this is not a widely used class with a very specific use. I could remove it if that makes things easier.
| # been pickled, so it can determine which Java broadcast objects to | ||
| # send. | ||
| self._pickled_broadcast_vars = set() | ||
| self._pickled_broadcast_registry = BroadcastPickleRegistry(self._lock) |
There was a problem hiding this comment.
Instead of using lock, how about use thread local data? So we don't block other threads when pickling.
BryanCutler
commented
Jul 26, 2017
Thanks @viirya , that was a good idea! I updated to use a thread-local object to store the pickled vars |
SparkQA
commented
Jul 26, 2017
Test build #79974 has finished for PR 18695 at commit
|
viirya
commented
Jul 28, 2017
The change LGTM. Will it be hard to add a reliable test for this? |
BryanCutler
commented
Jul 28, 2017
Yeah, I think I can add a simple test for this. I'll give it try. |
SparkQA
commented
Jul 31, 2017
Test build #80098 has finished for PR 18695 at commit
|
SparkQA
commented
Aug 1, 2017
Test build #80100 has finished for PR 18695 at commit
|
BryanCutler
commented
Aug 1, 2017
@viirya@HyukjinKwon , I added a test for this although maybe doesn't look as straightforward as I was thinking :) Could you take a look and see if it makes sense? Thanks! |
| def process_vars(sc): | ||
| broadcast_vars = [x for x in sc._pickled_broadcast_vars] | ||
| num_pickled = len(broadcast_vars) | ||
| sc._pickled_broadcast_vars.clear() |
There was a problem hiding this comment.
Shall we check if picked vars are actually cleared?
viirya
commented
Aug 1, 2017
LGTM except for one minor comment. |
| return _from_id, (self._jbroadcast.id(),) | ||
| class BroadcastPickleRegistry(threading.local): |
There was a problem hiding this comment.
Hm.. actually, I prefer the locking way before.. I guess It wouldn't be big performance differences due to GIL and simple lock was easy to read ...
There was a problem hiding this comment.
BTW, I am okay with the current way too.
There was a problem hiding this comment.
I'm ok for both ways. :)
My only concern is in previous locking way is we lock it for dumping the command. I'm not sure if the dumping can take long time for big command so we prevent other threads to preparing their commands.
There was a problem hiding this comment.
Yea, this anyway solves the issue and looks apparently safe from your concern. Probably, will make a follow up after testing it (quite) later.
There was a problem hiding this comment.
Using the lock was a little more obvious what is going on, but it's better to not use a lock in case of pickling a large command like @viirya said. Also, this way doesn't need to change any of the pickling code, so I prefer it too.
SparkQA
commented
Aug 1, 2017
Test build #80104 has finished for PR 18695 at commit
|
HyukjinKwon
commented
Aug 1, 2017
Last question to check if I read correctly. So, the problem is around |
HyukjinKwon
commented
Aug 1, 2017
BryanCutler
commented
Aug 1, 2017
Thanks @HyukjinKwon and @viirya! I updated the description. To sum up this issue, |
HyukjinKwon
commented
Aug 1, 2017
Thanks for clarification. LGTM |
Thanks. Merged to master. |
HyukjinKwon
commented
Aug 1, 2017
@holdenk, BTW, it looks I am facing the same issue you met before. Sounds I can't trigger the Jenkins build by "ok to test". Do you maybe know who I should ask and or some steps that I should take? |
felixcheung
commented
Aug 2, 2017
@HyukjinKwon that needs to be added separately by someone who has access to Jenkins as admin |
HyukjinKwon
commented
Aug 2, 2017
Hmm.. I see. Thanks. |
When using PySpark broadcast variables in a multi-threaded environment, `SparkContext._pickled_broadcast_vars` becomes a shared resource. A race condition can occur when broadcast variables that are pickled from one thread get added to the shared ` _pickled_broadcast_vars` and become part of the python command from another thread. This PR introduces a thread-safe pickled registry using thread local storage so that when python command is pickled (causing the broadcast variable to be pickled and added to the registry) each thread will have their own view of the pickle registry to retrieve and clear the broadcast variables used. Added a unit test that causes this race condition using another thread. Author: Bryan Cutler <cutlerb@gmail.com> Closesapache#18695 from BryanCutler/pyspark-bcast-threadsafe-SPARK-12717.
What changes were proposed in this pull request?
When using PySpark broadcast variables in a multi-threaded environment,
SparkContext._pickled_broadcast_varsbecomes a shared resource. A race condition can occur when broadcast variables that are pickled from one thread get added to the shared_pickled_broadcast_varsand become part of the python command from another thread. This PR introduces a thread-safe pickled registry using thread local storage so that when python command is pickled (causing the broadcast variable to be pickled and added to the registry) each thread will have their own view of the pickle registry to retrieve and clear the broadcast variables used.How was this patch tested?
Added a unit test that causes this race condition using another thread.