1

I have a SwingWorker actor which computes a plot for display from a parameters object it gets send; then draws the plot on the EDT thread. Some GUI elements can tweak parameters for this plot. When they change I generate a new parameter object and send it to the worker.

This works so far.

Now when moving a slider many events are created and queue up in the worker's mailbox. But I only need to compute the plot for the very last set of parameters. Is there a way to drop all messages from the inbox; keep the last one and process only that?

Currently the code looks like this

val worker = new SwingWorker {
  def act() {
    while (true) {
      receive {
        case params: ExperimentParameters => {
          //somehow expensive
          val result = RunExperiments.generateExperimentData(params)

          Swing.onEDT{ GuiElement.redrawWith(result) }
        }
      }
    }
  }
}
ziggystar
  • 28,410
  • 9
  • 72
  • 124
  • Can you define "last" more precisely? Is there any guarantee that there won't be any more messages? What if there is a large amount of delay before the last one arrives? I think you need (1) a timeout, or (2) mark the messages as `not-last` / `last`. – Jus12 Oct 07 '11 at 16:36
  • I thought this was clear from the problem I describe. Of course there can be more. But you should not start a job when there is another one after it *already available*. Because this means the older one is out of date and not needed anymore. – ziggystar Oct 07 '11 at 20:49

2 Answers2

2

Meanwhile I have found a solution. You can check the mailbox size of the actor and simply skip the message if it is not 0.

val worker = new SwingWorker {
  def act() {
    while (true) {
      receive {
        case params: ExperimentParameters => {
          if( mailboxSize == 0) {
            //somehow expensive
            val result = RunExperiments.generateExperimentData(params)
            Swing.onEDT{ GuiElement.redrawWith(result) }
          }
        }
      }
    }
  }
}
ziggystar
  • 28,410
  • 9
  • 72
  • 124
1

Remember the last event without processing it, have a very short timeout, process the last event when you get the timeout

could look like (not tested)

while(true) {
  var lastReceived : Option[ExperimentParameters] = None
  receive {case params : ExperimentParameters => lastReceived = Some(params)}
  while (!lastReceived.isEmpty) {
    receiveWithin(0) {
      case params: ExperimentParameters => lastReceived = Some(params)
      case TIMEOUT => do your job with lastReceived.get;
    }
  }
}
Didier Dupont
  • 29,398
  • 7
  • 71
  • 90
  • Thought about this solution, too. This has the property that you can wait for a little bit to aggregate more tasks. Whether you want this depends on the application. – ziggystar Oct 06 '11 at 11:23