@author johnmount @param type being observed @param type of observer that will work in parallel @param type of observer that will pre-scan serially
| 16 | * @param <S> type of observer that will pre-scan serially |
| 17 | */ |
| 18 | public final class ThreadedReducer<T, S extends SerialObserver<T>, Z extends ReducibleObserver<T,Z>> { |
| 19 | private final String logString; |
| 20 | private final int gulpSize = 1000; |
| 21 | private final int parallelism; |
| 22 | |
| 23 | public ThreadedReducer(final int parallelism, final String logString) { |
| 24 | this.parallelism = parallelism; |
| 25 | this.logString = logString; |
| 26 | } |
| 27 | |
| 28 | private final class EJob implements Runnable { |
| 29 | public final Z baseRes; |
| 30 | private final Iterable<? extends T> sourcei; |
| 31 | |
| 32 | public EJob(final Z baseRes, |
| 33 | final Iterable<? extends T> sourcei) { |
| 34 | this.baseRes = baseRes; |
| 35 | this.sourcei = sourcei; |
| 36 | } |
| 37 | |
| 38 | @Override |
| 39 | public void run() { |
| 40 | final Z r; |
| 41 | synchronized (baseRes) { |
| 42 | r = baseRes.newObserver(); |
| 43 | } |
| 44 | for(final T di: sourcei) { |
| 45 | r.observe(di); |
| 46 | } |
| 47 | synchronized (baseRes) { |
| 48 | baseRes.observe(r); |
| 49 | } |
| 50 | } |
| 51 | |
| 52 | } |
| 53 | |
| 54 | |
| 55 | /** |
| 56 | * |
| 57 | * @param dat data source |
| 58 | * @param serialObserver (option can be null) a cheap observer that will be applied to all data serially |
| 59 | * @param parallelObserver an expensive observer that will be applied in parallel |
| 60 | */ |
| 61 | public void reduce(final Iterable<? extends T> dat, final S serialObserver, final Z parallelObserver) { |
| 62 | final Ticker ticker = new Ticker(logString); |
| 63 | if(parallelism>1) { |
| 64 | final BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<Runnable>(2*parallelism + 10); |
| 65 | final ThreadPoolExecutor executor = new ThreadPoolExecutor(parallelism,parallelism,1000L,TimeUnit.SECONDS,workQueue); |
| 66 | ArrayList<T> al = new ArrayList<T>(gulpSize); |
| 67 | for(final T di: dat) { |
| 68 | ticker.tick(); |
| 69 | if(serialObserver!=null) { |
| 70 | serialObserver.observe(di); |
| 71 | } |
| 72 | al.add(di); |
| 73 | if(al.size()>=gulpSize) { |
| 74 | if((executor==null)||(executor.getTaskCount()-executor.getCompletedTaskCount()>parallelism)) { |
| 75 | new EJob(parallelObserver,al).run(); |
nothing calls this directly
no outgoing calls
no test coverage detected