-
-
Notifications
You must be signed in to change notification settings - Fork 1k
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
[ENH] Offload work to a separate thread #3627
Conversation
82c31bf
to
da32aa2
Compare
Codecov Report
@@ Coverage Diff @@
## master #3627 +/- ##
==========================================
+ Coverage 84.23% 84.28% +0.05%
==========================================
Files 370 372 +2
Lines 67469 67726 +257
==========================================
+ Hits 56832 57086 +254
- Misses 10637 10640 +3 |
Codecov Report
@@ Coverage Diff @@
## master #3627 +/- ##
==========================================
+ Coverage 84.34% 84.43% +0.08%
==========================================
Files 370 372 +2
Lines 67948 68220 +272
==========================================
+ Hits 57313 57599 +286
+ Misses 10635 10621 -14 |
6fa6114
to
12d4415
Compare
One major limitation of the current approach is that we can define only one single task by implementing One instance where this might be ugly would be when doing imputation. There are like 6 different ways to impute values, each of which presumably calls a different function. So in that case, To me, an ideal API would let me pass whatever function I want and run that on a thread, without having to override anything. Very similar to def very_complicated_task():
return 42
# Somewhere inside the widget
self.start(very_complicated_task) This wouldn't do anything with the progress bar or partial results or support cancelling, but we'd still get the result in This, then, introduces the problem: "How do we get the # ConcurrentWidgetMixin
def start(self, task: Callable):
""" Call to start the task. """
self.__cancel_task(wait=False)
if self.data is None:
self.__set_state_ready()
return
state = TaskState(self)
assert callable(task), "`task` must be callable!"
signature = inspect.signature(task)
for param in signature.parameters:
if issubclass(signature.parameters[param].annotation, TaskState):
task = partial(task, **{param: state})
self.__set_state_busy()
self.__start_task(task, state) then we could define our runner method accept a state e.g. def very_complicated_task(state: TaskState):
state.set_progress_value(50)
return 42
# Somewhere inside the widget
self.start(very_complicated_task) And boom. We can pass in simple functions or more complicated runners like in t-SNE, the API is very simple and straightforward. But it's magic. I am still unsure of how bad of an idea this is. Either way, I think we should try to remove |
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.
Having looked at this some more, I think we need to change our API a little bit. I'm opposed to having on_done
expose futures. The public API should be as simple as possible: start
, cancel
and shutdown
are quite clear. Handlers that we need to define on the widgets should be _on_partial_result
and _on_done
.
I realise now that there should be something to handle exceptions inside the thread _on_exception
. It should be simple to change the implementation of the current on_done
to check for an exception.
3217a99
to
ee8a726
Compare
d27978a
to
f8ebebe
Compare
f8ebebe
to
42ab1a0
Compare
42ab1a0
to
899fbfd
Compare
899fbfd
to
5d1ee30
Compare
5d1ee30
to
345e13f
Compare
345e13f
to
8ac9f33
Compare
Issue
Fixes #3579
Description of changes
runner
methods to calculate projectiona in threadsIncludes