001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.reef.wake.impl;
020
021import org.apache.reef.wake.AbstractEStage;
022import org.apache.reef.wake.EventHandler;
023
024import java.util.List;
025import java.util.concurrent.ExecutorService;
026import java.util.concurrent.Executors;
027import java.util.concurrent.TimeUnit;
028import java.util.logging.Logger;
029
030/**
031 * This stage uses a thread pool to schedule events in parallel.
032 * Should be used when input events are already materialized in a List and
033 * can be fired in any order.
034 *
035 * @param numThreads  fixed number of threads available in the pool
036 * @param granularity maximum number of events executed serially.
037 *                    The right choice will balance task spawn overhead with parallelism.
038 */
039public class IndependentIterationsThreadPoolStage<T> extends AbstractEStage<List<T>> {
040
041  private final int granularity;
042  private EventHandler<T> handler;
043  private ExecutorService executor;
044
045  public IndependentIterationsThreadPoolStage(
046      final EventHandler<T> handler, final int numThreads, final int granularity) {
047    super(handler.getClass().getName());
048    this.handler = handler;
049    this.executor = Executors.newFixedThreadPool(numThreads);
050    this.granularity = granularity;
051  }
052
053  private Runnable newTask(final List<T> iterations) {
054    return new Runnable() {
055      @Override
056      public void run() {
057        for (final T e : iterations) {
058          handler.onNext(e);
059        }
060      }
061    };
062  }
063
064  @Override
065  public void onNext(final List<T> iterations) {
066    Logger.getAnonymousLogger().info("Execute new task [" + iterations.size());
067    final int size = iterations.size();
068    for (int i = 0; i < size; i += granularity) {
069      int toIndex = i + granularity;
070      toIndex = toIndex > size ? size : toIndex;
071      executor.execute(newTask(iterations.subList(i, toIndex)));
072    }
073  }
074
075  @Override
076  public void close() throws Exception {
077    executor.shutdown();
078    executor.awaitTermination(1000, TimeUnit.DAYS);
079  }
080
081
082}