-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
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
[FEATURE] Task manager #3004
[FEATURE] Task manager #3004
Conversation
Sounds interesting. What's the use case for this? Processing? |
For Processing we already implemented mutithreading support and background tasks. Now waiting for 3.0 branch as it breaks Processing API. |
A couple of use cases:
Ideally processing would use this too. @alexbruy does this implementation look compatible with the processing background tasks? |
@wonder-sk There's something odd going on here. Eg, the following code
The TestTask.run method never actually gets called. I suspect there's something blocking this with PyQt and its handling of threads. https://riverbankcomputing.com/pipermail/pyqt/2011-February/029227.html makes me thing you may have hit this in the past... got any ideas? |
@nyalldawson we used similar approach. But seems we should drop our work and adopt Processing to use your task manager. |
@wonder-sk you're troubleshooting was spot-on. It was related to the task objects getting overwritten in Python. Here's a screencast of the Task Manager in action: This is using the sample code:
|
That looks amazing. What do you think about changing the icon to cancel the task? To me it looks like a "restart" icon rather than a "cancel" icon. |
Agreed on both points, @m-kuhn |
@m-kuhn yeah the icons are just placeholders for now... I reused existing ones, but I'll make some proper ones for this. |
Nice. One obvious task that comes to mind is those large composer exports (atlas et cie). Presumably the task would run in the background, have you planned a way to handle subsequent changes to project while the composer exports? |
b53cac3
to
cda5b92
Compare
Thanks to @NathanW2 there's a new high-level method for creating tasks from python functions without having to subclass QgsTask:
|
Is there still a todo list for this or is it ready for review? I think it's worth merging it soon to get a long testing period before the release. |
My TODO list would be:
|
Maybe parts can be split out and added in a second batch (e.g. support for tasks which cannot be cancelled or report their progress)? |
I'm hoping to get this stuff done today anyway :P if not, i'll defer it to later |
any reason to do not implement or plan pause and resume? |
@luipir good idea. I'll add it to the to-do list. |
It would also be nice to have dependencies. |
cda5b92
to
272f915
Compare
I very much like the approach from @NathanW2
Few more suggestions for C++ API:
|
Not supported in Py2 only in Py3 On Wed, Apr 20, 2016 at 2:16 PM, Martin Dobias notifications@github.com
|
+1 to showing tasks in the status bar. On Wed, Apr 20, 2016 at 2:17 PM, Nathan Woodrow madmanwoo@gmail.com wrote:
|
Following on from Martins comments about using yield. Here is an idea: Using the task object itself to report the status directly to thatl: def myfunc(task):
for i in range(100):
task.setProgress(i)
if i > 100:
raise Exception("Bam!")
if i > 200:
task.cancel()
return True This changes the task manager to be like this in the call: class QgsTaskWrapper(QgsTask):
def __init__(self, description, function, *extraArgs):
QgsTask.__init__(self, description, QgsTask.ProgressReport)
self.extraArgs = extraArgs
self.function = function
self.task_result = None
self.task_error = None
def run(self):
try:
self.function(self, *self.extraArgs)
expect Exception as ex:
# report error
return
self.completed() This design might be a bit clearer on intent and also lets you do this: class FakeTask:
def setProgess(self, status):
# Don't care
pass
myfunc(FakeTask) If you want to unit test or use out side of the task manager. The other option is to pass in it into the function as kwarg so it's optional for people: def myfunc(**kwargs):
# I don't care about reporting status so you can pass it in
# and I will just ignore it
# or kwargs['task'] if I do. class QgsTaskWrapper(QgsTask):
def __init__(self, description, function, *extraArgs):
QgsTask.__init__(self, description, QgsTask.ProgressReport)
self.extraArgs = extraArgs
.....
def run(self):
try:
extra = dict(task=self)
self.function(*self.extraArgs, **extra)
expect Exception as ex:
# report error
return
self.completed() |
@NathanW2 that's much nicer! I'll do that approach. |
272f915
to
d92d1eb
Compare
@wonder-sk I like the UI shots above. This makes me think the plugin update check-up could be one of the first bit ported to @nyalldawson 's task manager. Exciting stuff all around. |
possible for Qt < 5.5 Moral of the story: if you run outdated libraries, you can't expect full functionality from your apps ;)
Breaks returning list values
Instead use a private wrapper class to make QgsTask compatible with QThreadPool
Only allow starting tasks to be done by QgsTaskManager
Remove support for signal based completion/termination Also unfortunately disable a lot of the test suite as a result, since it's not easily translatable
66c87f7
to
d03d0a5
Compare
@wonder-sk Ok, I've implemented everything you suggested, with the exceptions from my original response. (ie, I consider this complete now ;) ) |
@nyalldawson Awesome! Thanks a lot for that! For sub-tasks, your recent updates make my previous concerns invalid (for progress hijacking I must have misread the code, sorry). For copy_func(), I would suggest we either remove it or add a note why it is necessary... +100 from me, please merge! 🎉 |
Thanks @wonder-sk
I'll kill it.. like I said, it was an attempt to solve an unrelated crash which I'd just left in for safety. Easy enough to re-introduce if it's solving a real problem in future. |
Merged! Thanks to everyone for all the detailed feedback and suggestions, and for the QGIS org for the grant to finish this off! :D |
Prototype work in implementing a task manager for QGIS, with easy handling of submitting tasks to be run in the background and exposing their status to users.
Adds new classes:
isCancelled()
to gracefully abort.A new dock widget has been added with a task manager widget showing global tasks.
You can test with the following code:
Note that I get crashes with this. My suspicion is that it's due to some oddness in SIP, but it's quite possible there's bugs in the code too!
@wonder-sk Would appreciate you taking a look at this version!