|
See ma? They're running there...
So continuing my last post I decided to build an easy-to-use SwingWorkerManager to
monitor how my SwingWorkers run in the wild.
I've built a SwingWorkerManager.getInstance() singleton to which I "submit( SwingWorker )"
for execution. The SwingWorkerManager has a little ListModel that keeps track of
the last executed SwingWorkers (by adding PropertyChangeListeners to them) and monitors their
activity.
Apart of this ListModel the SwingWorkerManager can create also a ListCellRenderer to better
visualize SwingWorker progress.
Source code (LGPL'ed) is available. Of course you can also
run this little Java WebStart demo (note: JDK 5.0 required). Instructions
for using the SwingWorkerManager are included in the javadoc documentation.
Sizing the pool...
So as I said before this SwingWorkerManager uses an internal thread pool to
execute SwingWorkers. As Jeffrey wisely pointed out in his comment, the size of the
pool should depend on the number of available processors NCPU in the environment (that is,
it should be a linear function of NCPU=Runtime.getRuntime().availableProcessors()). So,
continuing our previous discussion:
M = F * NCPU < N
Where M is the number of threads in the pool, F is a constant, NCPU is
the number of CPUs in the system and N is the number of scheduled tasks.
Since usually many threads are just waiting for I/O it would be a waste of time to set
F=1 (since then many CPUs would be just hanging around waiting for I/O). So I think
a good F value could be around 3. That way we'll kick those lazy CPUs. You know, CPU speeds
are very high nowadays, and CPU cycles are probably cheaper than any other kind of resource.
So let's assume F=3 is a good bet. Are we missing something? Well, er.. what about
those slow ones?
Come on, you lazy one, hurry up, get out of my way...
Assume you're downloading a 10 Gb file from somewhere. You, of course, want to use a SwingWorker
for that. But that's gonna take quite some time. And we're using a fixed thread pool, right?
So that task is going to reduce the size of our fixed thread pool (and, thus, reduce
the responsiveness of our GUI).
How could we handle this? Well, two solutions come to mind...
- a) Increase M slightly to make room for these slow ones.
- b) Use another fixed thread pool to schedule these very long-running, very time-consuming
slow processes.
- c) Use one of the above and provide a timeout setting for scheduling tasks.
That way those tasks that have not finished before the given timeout value would be automatically interrupted.
The two first ones are not difficult to implement...
Solution a) would require this value for M:
M = F * NCPU + SLOW < N
Where SLOW is a fixed value that approximates the number of simultaneous slow
processes you think may be running in your application.
And solution b) would require adding a new fixed thread pool (of size, say, SLOW) and a new
method (say "submitSlowTask( SwingWorker )") that schedules things into this new
fixed thread pool.
The third solution won't be too difficult to implement, either (by slightly increasing M to allocate
timeout watcher SwingWorkers).
What do you think? Which one do you like best? Come on, give me a hand here! ;-)
The wonderfully complex world of task scheduling
Many Task Scheduling algorithms are NP hard problems.
The SwingWorkerManager presented here implements a simple FIFO (First In-First Out)
solution to scheduling SwingWorkers in a set of threads.
SwingWorkerManager may be a good way to experiment different task scheduling algorithms (say, in a
Computer Science classroom), but I think a FIFO is good enough for me. And, of course, I can watch my SwingWorkers
running. See ma? I hope it's good for you too (and if not, then just complain here! ;-)).
Please let me know of any improvements or bugs.
Happy swinging,
Antonio
|
Enviado por Jeffrey Olson en enero 19, 2006 a las 10:03 PM CET #
I'd say a combo of a & b... A pool of slow ones using the (f * ncpu) then possible a fast pool from that that can be interupted and if a submition gets interupted a few times it gets submitted to the slow pool?
fast = z, where z is some value > 0
slow = (f * ncpu) - fast
M = fast + slow < N
And I'd assume if you had a slow pool, and if nothing was being processed by them you could just pass things off to those for processing as well just to free up the fast pool faster. Just my thoughts!
Also, awesome job! =)
Enviado por Jeffrey Olson en enero 19, 2006 a las 10:09 PM CET #
Yes, I'm aware of the bugs in the comments. I've already posted some bugs reports to the blog guys.
That's a nice idea of yours. Maybe it's a good idea to have two different lanes for scheduling. A fast one (so small simple tasks get executed faster and a long one, probably with a lower thread priority). I'll think of it.
And I think that being able to cancel SwingWorkers from within the list (or Table?) may be a good enhancement as well. (And probably approximating a possible "time to finish" value too).
I think that SwingWorkerManager may be a good companion for an event bus.
Thanks for your tips,
Antonio
Enviado por Antonio en enero 20, 2006 a las 11:12 AM CET #
Thanks again,
Antonio
Enviado por Antonio en enero 20, 2006 a las 11:17 AM CET #
Enviado por Trey en enero 25, 2006 a las 12:45 PM CET #
Oh, NetBeans has components for visually displaying running tasks, too.
On the other hand I have not the faintest idea about what the Eclipse Progress panel looks like. (I don't use Eclipse, sorry).
Cheers,
Antonio
Enviado por Antonio en enero 27, 2006 a las 10:32 AM CET #
Enviado por hjh en febrero 06, 2006 a las 01:58 PM CET #