All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.twitter.cassovary.util.ExecutorUtils.scala Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2014 Twitter, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
 * file except in compliance with the License. You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed
 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 * CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */
package com.twitter.cassovary.util

import com.google.common.util.concurrent.ThreadFactoryBuilder
import com.twitter.ostrich.stats.Stats
import com.twitter.util.Duration
import java.util.ArrayList
import java.util.concurrent._
import java.util.{List => JList}

/**
 * Utility class for unbounded and bounded parallel execution
 */
object ExecutorUtils {

  private def rejectedExecutionHandlerFactory(name: String,
      handler: => Unit): RejectedExecutionHandler = {
    new RejectedExecutionHandler {
      def rejectedExecution(r: Runnable, executor: ThreadPoolExecutor) {
        handler
      }
    }
  }

  /**
   * Creates an {@link java.util.concurrent.ExecutorService} with bounded work queue and fixed lower
   * and upper bounds on the thread pool size used to service the work queue.  The returned executor
   * service will export stats monitoring queue depth, active thread count and rejections due to
   * queue full conditions.
   *
   * 

The supplied config map requires the following configuration keys: *

    *
  • max_work_queue_depth *
  • min_num_worker_threads *
  • max_num_worker_threads *
  • max_worker_idle_time_millis *
*/ def createBoundedExecutorService(name: String, config: String => Int) (rejectedExecutionHandler: => Unit): ExecutorService = { createBoundedExecutorService(name, config("max_work_queue_depth"), config("min_num_worker_threads"), config("max_num_worker_threads"), Duration.fromTimeUnit(config("max_worker_idle_time_millis").toInt, TimeUnit.MILLISECONDS))(rejectedExecutionHandler) } /** * Creates an {@link java.util.concurrent.ExecutorService} with bounded work queue and fixed lower * and upper bounds on the thread pool size used to service the work queue. The returned executor * service will export stats monitoring queue depth, active thread count and rejections due to * queue full conditions. */ def createBoundedExecutorService(name: String, maxWorkQueueDepth: Int, minThreads: Int, maxThreads: Int, maxIdleTime: Duration) (rejectedExecutionHandler: => Unit): ExecutorService = { val taskQueue = new LinkedBlockingQueue[Runnable](maxWorkQueueDepth) val threadPoolExecutor = new ThreadPoolExecutor( minThreads, maxThreads, maxIdleTime.inMillis, TimeUnit.MILLISECONDS, taskQueue, createThreadFactory(name), rejectedExecutionHandlerFactory(name, rejectedExecutionHandler)) Stats.addGauge(name + "_queue_depth") { taskQueue.size } createPoolStats(name, threadPoolExecutor) threadPoolExecutor } private def createThreadFactory(name: String) = { new ThreadFactoryBuilder().setDaemon(true).setNameFormat(name + "[%d]").build } private def createPoolStats(name: String, threadPoolExecutor: ThreadPoolExecutor): Unit = { Stats.addGauge(name + "_threads_active") { threadPoolExecutor.getActiveCount } Stats.addGauge(name + "_max_threads_active") { threadPoolExecutor.getLargestPoolSize } } /** * Farm out separate threads using an ExecutorService to perform work on inputs * @param executorService the ExecutorService to use for parallelization * @param inputs a sequence of inputs to work on * @param work the work to apply to the inputs */ def parallelWork[T, A](executorService: ExecutorService, inputs: Seq[T], work: T => A): JList[Future[A]] = { val workTasks = { val tasks = new ArrayList[Callable[A]](inputs.size) inputs foreach { input => tasks.add(new Callable[A]() { def call(): A = { work(input) } }) } tasks } executorService.invokeAll(workTasks) } /** * Farm out separate threads using an ExecutorService to perform * work on inputs. Unlike [[ExecutorUtils.parallelWork]], no values * are returned. If an exception occurs in a worker thread, it is * rethrown on the calling thread. * @param executorService the ExecutorService to use for parallelization * @param inputs a sequence of inputs to work on * @param work the work to apply to the inputs */ def parallelForEach[T, A](executorService: ExecutorService, inputs: Seq[T], work: T => A): Unit = { import scala.collection.JavaConversions._ parallelWork(executorService, inputs, work) foreach { _.get } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy