Sascha L. Teichmann a écrit :

>Really back to topic:
>
>Find attached a replacement for ThreadQueue [1].
>To use it just overwrite the original one.
>  
>
Hi Sascha :

I think that trying to have a cleaner and more simple code is an 
excellent goal, and I'd like to help, but I'm not sure I can understand 
all these thread issues.
If you tell me exactly which classes I must replace (on ly ThreadQueue 
or also the pieces of code from your previous mail) and what kind of 
tests I should do (rendering different kind of layers ? mixing different 
kind of layers), I'll try to make some more tests on my desktop.

Thanks, for the hard work

Michaël

>This one works for the real parallel case of
>layer rendering too. Each time a thread finished
>executing its Runnable it looks into the queue
>if they are more jobs to do. This prevents unnecessary
>thread creations/shutdowns. If the queue is empty
>the worker thread is kept alive for 5 seconds waiting
>for new jobs. This results in a kind of thread pooling.
>
>@Larry: I've isolated my implementation and the OJ
>ThreadQueue and done a synthetic benchmark with a
>larger number of jobs (10,000+). My implementation
>works about two orders faster than the OJ one.
>But this is of little meaning because OJ only
>has to handle a number of jobs equal the number
>of layers. This will hardly hit 10,000+ ;-)
>But again: My mission is improve the structure not
>primarily the speed.
>
>I've tested the new ThreadQueue to some extent but
>I'am male(tm) after all ... potentially making mistakes.
>It would be very kind if someone test it too.
>
>My next step will be some clean up in the RenderingManager [2].
>I'am not sure that it is really needed to have two ThreadQueues
>there. The effect of the single tread one can be easily
>simulated with a data structure like the RunnableArrayList which
>I've posted already.
>
>Any comments?
>
>Yours,
>  Sascha
>
>[1] com.vividsolutions.jump.workbench.ui.renderer.ThreadQueue
>[2] com.vividsolutions.jump.workbench.ui.renderer.RenderingManager
>
>Sunburned Surveyor schrieb:
>  
>
>>Sascha,
>>
>>Please accept my sincerest aopologies. I'm afriad my American
>>ignorance of other cultures is more than just a little obvious at
>>times.
>>
>>I believe I have made the same mistake with Jan. :]
>>
>>Please be patient with me as I learn the details of cultures across
>>the Pacific and Atalantic Oceans!
>>
>>The Sunburned Surveyor
>>
>>On 5/24/07, Sascha L. Teichmann <[EMAIL PROTECTED]> wrote:
>>    
>>
>>>TNX, but for the records 'he' would be more suited in my case.
>>>
>>>'Sascha' is basically a Russian term of endearment for the
>>>boys name 'Alexander' but it's also used as a girls name.
>>>
>>>BTW: 'Jan' is a girls name in the US too, isn't? ;-)
>>>
>>>- Sascha
>>>
>>>
>>>Sunburned Surveyor schrieb:
>>>      
>>>
>>>>Sascha and Larry,
>>>>
>>>>I must admit that I am way over my head here. I haven't done much
>>>>thread programming in Java. (Hopefully Stefan has!)
>>>>
>>>>Sascha wrote: "My primary goal is to simplify the
>>>>threading code to make it more reliable in terms of time."
>>>>
>>>>This seems like an admirable goal to me. If Larry, or a similar
>>>>programmer of his experience, agrees that this changes would be
>>>>beneficial, I say we give Sascha a shot at it. It sounds like she has
>>>>considered her changes carefully.
>>>>
>>>>Just my two cents.
>>>>
>>>>The Sunburned Surveyor
>>>>
>>>>
>>>>
>>>>On 5/24/07, Sascha L. Teichmann <[EMAIL PROTECTED]> wrote:
>>>>        
>>>>
>>>>>Hi Larry,
>>>>>
>>>>>short answer first: No, I don't have any benchmarks, yet.
>>>>>
>>>>>The long answer: My primary goal is to simplify the
>>>>>threading code to make it more reliable in terms of time.
>>>>>Gaining performance improvements would be a neat side effect.
>>>>>
>>>>>Background: Multi-threading may be fine for slow layers
>>>>>which arrives later on the screen but for exporting
>>>>>the data (to print/layout e.g) it would be nice to have
>>>>>them arriving one after the other.
>>>>>
>>>>>My final goal is to have a simple switch between the normal
>>>>>and the serial mode. To archive that I try to carefully
>>>>>refactor the system doing little patches step by step
>>>>>not to break it. Refactoring the ThreadQueue with it's
>>>>>'flaws' seems a to be a good starting point to me.
>>>>>
>>>>>One reason for this change is the fact that you are able
>>>>>to figure out if the default thread runs empty. But there
>>>>>is no way to figure out when the last thread ends. That
>>>>>are different things. A mechanism for this is planned.
>>>>>
>>>>>Sorry, if I've shadowed my true intentions to much. Maybe
>>>>>I should discuss more before I send patches.  ;-)
>>>>>
>>>>>Back to the technical side:
>>>>>
>>>>>The patch needs some testing but I don't expect too much
>>>>>performance improvement.
>>>>>
>>>>>A less intrusive alternative to bind the Runnables that go to the
>>>>>default ThreadQueue into one thread is to create a container
>>>>>which self is Runnable (see e.g. RunnableArrayList attached)
>>>>>and put them into an instance of this class.
>>>>>This container is put into multiRendererThreadQueue as a Runnable.
>>>>>With this modification the defaultRendererThreadQueue can
>>>>>be removed (multiRendererThreadQueue renamed to
>>>>>defaultRendererThreadQueue). Only an idea ... I'm in discussion
>>>>>mode now. ;-)
>>>>>
>>>>>- Sascha
>>>>>
>>>>>
>>>>>Larry Becker schrieb:
>>>>>          
>>>>>
>>>>>>Hi Sascha,
>>>>>>
>>>>>>  I read your comments and look at your code with interest.  It appears
>>>>>>to be an improved ThreadQueue implementation, but will require a lot of
>>>>>>testing to verify.  Before I invest this time, I would like to know what
>>>>>>problem it is solving.  I see your dislikes a - e, but these are not
>>>>>>really problems, only architectural critiques.  Have you done any
>>>>>>benchmarks that show that the new SingleThreadQueue speeds up
>>>>>>rendering?  Your logical argument that it should be more efficient  is
>>>>>>persuasive,  but  I have been surprised by Java before.
>>>>>>
>>>>>>respectfully,
>>>>>>Larry Becker
>>>>>>
>>>>>>On 5/23/07, *Sascha L. Teichmann* <[EMAIL PROTECTED]
>>>>>><mailto:[EMAIL PROTECTED]>> wrote:
>>>>>>
>>>>>>    Hi together,
>>>>>>
>>>>>>    as some of you may already know i have my dislikes against
>>>>>>    ThreadQueue [1] (Hi, Larry!) see my mail [2]
>>>>>>
>>>>>>    a - It forks a new thread for any Runnable it processes.
>>>>>>    b - It has an ugly busy wait loop inside.
>>>>>>    c - The event listener for empty queue fires to often.
>>>>>>    d - The default ThreadQueue is some kind of thread serializer.
>>>>>>    e - The DB/WMS ThreadQueue has no public access.
>>>>>>
>>>>>>    Now I've written a sub class of ThreadQueue: SingleThreadQueue
>>>>>>    (see attachment). This one deals with the issues a, b and d.
>>>>>>    I also attached a patch against RenderingManager [3] to handle e.
>>>>>>
>>>>>>    The new class (to be placed in package
>>>>>>    com.vividsolutions.jump.workbench.ui.renderer) is a drop-in
>>>>>>    replacement for the default ThreadQueue in RenderingManager.
>>>>>>    Not for the ThreadQueue that handles the DB/WMS layers.
>>>>>>
>>>>>>    Because Jon limited the number of parallel threads in default
>>>>>>    queue to 1 I see no reason why to fork a new thread for each
>>>>>>    Runnable it processes. Thread creation/shutdown is fairly
>>>>>>    expensive. Instead a single background thread is started
>>>>>>    which processes the Runnables one by one. If the thread
>>>>>>    is idle for 30 secs it shuts itself down. If you have a lot
>>>>>>    of (non-WMS/BB) layers this should improve performance
>>>>>>    and save some resources. The processing itself is done
>>>>>>    with a monitor (synchronized/wait/notify) so there is no
>>>>>>    busy wait any more.
>>>>>>
>>>>>>    The DB/WMS ThreadQueue (real parallel threads) is left untouched
>>>>>>    for the moment. Depending on my personal schedule I will send
>>>>>>    a patch against this one too. Preliminary code with thread pooling
>>>>>>    exists but it needs a bit more testing.
>>>>>>
>>>>>>    Find attached the new class and patches against RenderingManager and
>>>>>>    the old ThreadQueue to bring it to work.
>>>>>>
>>>>>>    Comments are very welcome. :-)
>>>>>>
>>>>>>    Kind regrads,
>>>>>>      Sascha
>>>>>>
>>>>>>    [1] com.vividsolutions.jump.workbench.ui.renderer.ThreadQueue
>>>>>>    [2]
>>>>>>    
>>>>>> http://sourceforge.net/mailarchive/message.php?msg_name=4653389E.6000706%40intevation.de
>>>>>>    [3] com.vividsolutions.jump.workbench.ui.renderer.RenderingManager
>>>>>>
>>>>>>            
>>>>>>
>>>>>>------------------------------------------------------------------------
>>>>>>
>>>>>>/*
>>>>>> * The Unified Mapping Platform (JUMP) is an extensible, interactive GUI 
>>>>>> * for visualizing and manipulating spatial features with geometry and 
>>>>>> attributes.
>>>>>> *
>>>>>> * Copyright (C) 2003 Vivid Solutions 
>>>>>> * Copyright (C) 2007 Intevation GmbH
>>>>>> * 
>>>>>> * This program is free software; you can redistribute it and/or
>>>>>> * modify it under the terms of the GNU General Public License
>>>>>> * as published by the Free Software Foundation; either version 2
>>>>>> * of the License, or (at your option) any later version.
>>>>>> * 
>>>>>> * This program is distributed in the hope that it will be useful,
>>>>>> * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>>>>> * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>>>>> * GNU General Public License for more details.
>>>>>> * 
>>>>>> * You should have received a copy of the GNU General Public License
>>>>>> * along with this program; if not, write to the Free Software
>>>>>> * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 
>>>>>> USA.
>>>>>> * 
>>>>>> * Suite #1A
>>>>>> * 2328 Government Street
>>>>>> * Victoria BC  V8T 5G5
>>>>>> * Canada
>>>>>> *
>>>>>> * (250)385-6040
>>>>>> * www.vividsolutions.com
>>>>>> */
>>>>>>package com.vividsolutions.jump.workbench.ui.renderer;
>>>>>>
>>>>>>import java.util.LinkedList;
>>>>>>import java.util.ArrayList;
>>>>>>
>>>>>>/**
>>>>>> * This thread queue executes at maximum N Runnables in parallel
>>>>>> * were N is a given number of worker threads that should be used.
>>>>>> * If N threads are running and busy each further incoming 
>>>>>> * Runnable is queued until one of the threads has finished its current 
>>>>>> job.
>>>>>> * If a worker thread becomes idle (no more job in the queue)
>>>>>> * it is hold alive for 5 seconds. If during this period of time 
>>>>>> * no new Runnable is enqueued the worker thread dies.
>>>>>> *
>>>>>> * @author Sascha L. Teichmann ([EMAIL PROTECTED])
>>>>>> */
>>>>>>public class ThreadQueue
>>>>>>{
>>>>>>  /** The time a worker thread stays alive if idle */
>>>>>>  public static final long WORKER_STAY_ALIVE_TIME = 5000L;
>>>>>>
>>>>>>  /**
>>>>>>   * Worker thread. Fetches Runnable from the surrounding 
>>>>>>   * ThreadQueue instance.
>>>>>>   */
>>>>>>  protected class Worker 
>>>>>>  extends         Thread
>>>>>>  {
>>>>>>          public void run() {
>>>>>>                  try {
>>>>>>                          for (;;) {
>>>>>>                                  Runnable runnable;
>>>>>>
>>>>>>                                  synchronized (queuedRunnables) {
>>>>>>                                          if (queuedRunnables.isEmpty()) {
>>>>>>                                                  ++waitingThreads;
>>>>>>                                                  try {
>>>>>>                                                          
>>>>>> queuedRunnables.wait(WORKER_STAY_ALIVE_TIME);
>>>>>>                                                  }
>>>>>>                                                  catch 
>>>>>> (InterruptedException ie) {
>>>>>>                                                  }
>>>>>>                                                  finally {
>>>>>>                                                          
>>>>>> --waitingThreads;
>>>>>>                                                  }
>>>>>>
>>>>>>                                                  // if still empty -> 
>>>>>> die!
>>>>>>                                                  if 
>>>>>> (queuedRunnables.isEmpty())
>>>>>>                                                          break;
>>>>>>                                          }
>>>>>>                                          if (disposed)
>>>>>>                                                  break;
>>>>>>                                          runnable = 
>>>>>> (Runnable)queuedRunnables.remove();
>>>>>>                                  } // synchronized queuedRunnables
>>>>>>
>>>>>>                                  try {
>>>>>>                                          runnable.run();
>>>>>>                                  }
>>>>>>                                  catch (Exception e) {
>>>>>>                                          e.printStackTrace();
>>>>>>                                  }
>>>>>>                          } // for (;;)
>>>>>>                  }
>>>>>>                  finally { // guarantee that counter goes down
>>>>>>                          boolean allRunningThreadsFinished;
>>>>>>                          synchronized (runningThreads) {
>>>>>>                                  allRunningThreadsFinished = 
>>>>>> --runningThreads[0] == 0;
>>>>>>                          }
>>>>>>                          if (allRunningThreadsFinished)
>>>>>>                                  fireAllRunningThreadsFinished();
>>>>>>                  }
>>>>>>          }
>>>>>>  } // class Worker
>>>>>>
>>>>>>  /**
>>>>>>   * If the number of running threads goes down to zero
>>>>>>   * implementations of this interface are able to be informed.
>>>>>>   */
>>>>>>  public interface Listener {
>>>>>>          void allRunningThreadsFinished();
>>>>>>  } // interface Listener
>>>>>>
>>>>>>  /** Number of running threads */
>>>>>>  protected int [] runningThreads = new int[1];
>>>>>>
>>>>>>  /** max. Number of threads running parallel */
>>>>>>  protected int maxRunningThreads;
>>>>>>
>>>>>>  /** Number of threads that are currently idle */
>>>>>>  protected int waitingThreads;
>>>>>>
>>>>>>  /** The queue of Runnables jobs waiting to be run */
>>>>>>  protected LinkedList queuedRunnables;
>>>>>>
>>>>>>  /** Singals that the ThreadQueue is going to quit */
>>>>>>  protected boolean disposed;
>>>>>>
>>>>>>  /** List of Listeners */
>>>>>>  protected ArrayList listeners = new ArrayList();
>>>>>>
>>>>>>  /**
>>>>>>   * Creates a ThreadQueue with one worker thread.
>>>>>>   */
>>>>>>  public ThreadQueue() {
>>>>>>          this(1);
>>>>>>  }
>>>>>>
>>>>>>  /** Creates a ThreadQueue with a given number of worker threads.
>>>>>>   * @param maxRunningThreads the max. number of threads to be run 
>>>>>> parallel.
>>>>>>   */
>>>>>>  public ThreadQueue(int maxRunningThreads) {
>>>>>>          this.maxRunningThreads = Math.max(1, maxRunningThreads);
>>>>>>          queuedRunnables = new LinkedList();
>>>>>>  }
>>>>>>
>>>>>>  /**
>>>>>>   * Adds a Listener to this ThreadQueue.
>>>>>>   * @param listener the listener to add.
>>>>>>   */
>>>>>>  public synchronized void add(Listener listener) {
>>>>>>          if (listener != null)
>>>>>>                  listeners.add(listener);
>>>>>>  }
>>>>>>
>>>>>>  /**
>>>>>>   * Removes a Listener from this ThreadQueue.
>>>>>>   * @param listener the listener to be removed.
>>>>>>   */
>>>>>>  public synchronized void remove(Listener listener) {
>>>>>>          if (listener != null)
>>>>>>                  listeners.add(listener);
>>>>>>  }
>>>>>>
>>>>>>  /**
>>>>>>   * Informs Listeners of the fact that the number of running threads
>>>>>>   * went to zero.
>>>>>>   */
>>>>>>  protected void fireAllRunningThreadsFinished() {
>>>>>>          ArrayList copy;
>>>>>>          synchronized (this) { copy = new ArrayList(listeners); }
>>>>>>          for (int i = copy.size()-1; i >= 0; --i)
>>>>>>                  ((Listener)copy.get(i)).allRunningThreadsFinished();
>>>>>>  }
>>>>>>
>>>>>>
>>>>>>  /**
>>>>>>   * The number of currently running worker threads.
>>>>>>   * @return number of currently running worker threads.
>>>>>>   */
>>>>>>  public int runningThreads() {
>>>>>>          synchronized (runningThreads) {
>>>>>>                  return runningThreads[0];
>>>>>>          }
>>>>>>  }
>>>>>>
>>>>>>  /**
>>>>>>   * The number of currently waiting Runnables.
>>>>>>   * @return number of currently waiting Runnables.
>>>>>>   */
>>>>>>  public int waitingRunnables() {
>>>>>>          synchronized (runningThreads) {
>>>>>>                  return queuedRunnables.size();
>>>>>>          }
>>>>>>  }
>>>>>>
>>>>>>  /**
>>>>>>   * The number of currently idle worker threads.
>>>>>>   * @return number of currently idle worker threads.
>>>>>>   */
>>>>>>  public int waitingThreads() {
>>>>>>          synchronized (queuedRunnables) {
>>>>>>                  return waitingThreads;
>>>>>>          }
>>>>>>  }
>>>>>>
>>>>>>  /**
>>>>>>   * Adds a Runnables to the queue. It will be run in one
>>>>>>   * of the worker threads.
>>>>>>   * @param runnable The Runnables to add
>>>>>>   */
>>>>>>  public void add(Runnable runnable) {
>>>>>>          int waiting;
>>>>>>          synchronized (queuedRunnables) {
>>>>>>                  if (disposed)
>>>>>>                          return;
>>>>>>                  waiting = waitingThreads;
>>>>>>                  queuedRunnables.add(runnable);
>>>>>>                  queuedRunnables.notify();
>>>>>>          }  // synchronized (queuedRunnables)
>>>>>>
>>>>>>          synchronized (runningThreads) {
>>>>>>
>>>>>>                  // if waitingThreads == 1 then
>>>>>>                  // the queuedRunnables.notify() should have waked it up.
>>>>>>
>>>>>>                  if (waitingThreads < 2 && runningThreads[0] < 
>>>>>> maxRunningThreads) {
>>>>>>                          ++runningThreads[0];
>>>>>>                          Worker w = new Worker();
>>>>>>                          w.setDaemon(true);
>>>>>>                          w.start();
>>>>>>                  }
>>>>>>          } // synchronized (runningThreads)
>>>>>>  }
>>>>>>
>>>>>>  /**
>>>>>>   * Empties the queue of waiting Runnables.
>>>>>>   */
>>>>>>  public void clear() {
>>>>>>          synchronized (queuedRunnables) {
>>>>>>                  queuedRunnables.clear();
>>>>>>          }
>>>>>>  }
>>>>>>
>>>>>>  /**
>>>>>>   * Shuts down the ThreadQueue.
>>>>>>   */
>>>>>>  public void dispose() {
>>>>>>          synchronized (queuedRunnables) {
>>>>>>                  disposed = true;
>>>>>>                  queuedRunnables.clear();
>>>>>>                  // wakeup idle threads
>>>>>>                  queuedRunnables.notifyAll();
>>>>>>          }
>>>>>>          synchronized (this) {
>>>>>>                  listeners.clear();
>>>>>>          }
>>>>>>  }
>>>>>>}
>>>>>>// end of file
>>>>>>            
>>>>>>
>>>>>>------------------------------------------------------------------------
>>>>>>
>>>>>>-------------------------------------------------------------------------
>>>>>>This SF.net email is sponsored by DB2 Express
>>>>>>Download DB2 Express C - the FREE version of DB2 express and take
>>>>>>control of your XML. No limits. Just data. Click to get it now.
>>>>>>http://sourceforge.net/powerbar/db2/
>>>>>>
>>>>>>------------------------------------------------------------------------
>>>>>>
>>>>>>_______________________________________________
>>>>>>Jump-pilot-devel mailing list
>>>>>>Jump-pilot-devel@lists.sourceforge.net
>>>>>>https://lists.sourceforge.net/lists/listinfo/jump-pilot-devel
>>>>>>            
>>>>>>


-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
Jump-pilot-devel mailing list
Jump-pilot-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jump-pilot-devel

Reply via email to