kr.debop4j.core.parallelism.Parallels.java Source code

Java tutorial

Introduction

Here is the source code for kr.debop4j.core.parallelism.Parallels.java

Source

/*
 * Copyright 2011-2013 the original author or authors.
 *
 * 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 kr.debop4j.core.parallelism;

import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import kr.debop4j.core.Action1;
import kr.debop4j.core.Function1;
import kr.debop4j.core.collection.NumberRange;
import lombok.Getter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

import static kr.debop4j.core.Guard.shouldNotBeNull;

/**
 *  ???   ?   ??  Class .
 *
 * @author ? ( sunghyouk.bae@gmail.com )
 * @since 12. 9. 26.
 */
public abstract class Parallels {

    private static final Logger log = LoggerFactory.getLogger(Parallels.class);
    private static final boolean isTraceEnabled = log.isTraceEnabled();
    private static final boolean isDebugEnabled = log.isDebugEnabled();

    private Parallels() {
    }

    @Getter(lazy = true)
    private static final ThreadLocalRandom random = ThreadLocalRandom.current();
    @Getter(lazy = true)
    private static final int processCount = Runtime.getRuntime().availableProcessors();
    @Getter(lazy = true)
    private static final int workerCount = getProcessCount() * 2;

    /**
     * Create executor.
     *
     * @return the executor service
     */
    public static ExecutorService createExecutor() {
        return createExecutor(getWorkerCount());
    }

    /**
     * Create executor.
     *
     * @param threadCount the thread count
     * @return the executor service
     */
    public static ExecutorService createExecutor(int threadCount) {
        return Executors.newFixedThreadPool(threadCount);
    }

    private static int getPartitionSize(int itemCount, int partitionCount) {
        return (itemCount / partitionCount) + ((itemCount % partitionCount) > 0 ? 1 : 0);
    }

    /**
     *  ?  .  @param count the count
     *
     * @param runnable the runnable
     */
    public static void run(int count, final Runnable runnable) {
        run(0, count, runnable);
    }

    /**
     * Run void.
     *
     * @param fromInclude the from include
     * @param toExclude   the to exclude
     * @param action      the action
     */
    public static void run(int fromInclude, int toExclude, final Runnable action) {
        int step = (fromInclude <= toExclude) ? 1 : -1;
        run(fromInclude, toExclude, step, action);
    }

    /**
     * Run void.
     *
     * @param fromInclude the from include
     * @param toExclude   the to exclude
     * @param step        the step
     * @param runnable    the runnable
     */
    public static void run(int fromInclude, int toExclude, int step, final Runnable runnable) {
        assert runnable != null;

        if (log.isDebugEnabled())
            log.debug(
                    " ? ... fromInclude=[{}], toExclude=[{}], step=[{}], workerCount=[{}]",
                    fromInclude, toExclude, step, getWorkerCount());

        ExecutorService executor = Executors.newFixedThreadPool(getWorkerCount());

        try {
            List<NumberRange.IntRange> partitions = NumberRange.partition(fromInclude, toExclude, step,
                    getWorkerCount());
            List<Callable<Void>> tasks = Lists.newLinkedList();

            for (final NumberRange.IntRange partition : partitions) {
                Callable<Void> task = new Callable<Void>() {
                    @Override
                    public Void call() throws Exception {
                        for (final int element : partition)
                            runnable.run();
                        return null;
                    }
                };
                tasks.add(task);
            }

            List<Future<Void>> results = executor.invokeAll(tasks);
            for (Future<Void> result : results) {
                result.get();
            }

            if (log.isDebugEnabled())
                log.debug(" ? !");

        } catch (Exception e) {
            log.error("???      ?.", e);
            throw new RuntimeException(e);
        } finally {
            executor.shutdown();
        }
    }

    /**
     * Run void.
     *
     * @param count  the count
     * @param action the action
     */
    public static void run(int count, final Action1<Integer> action) {
        run(0, count, action);
    }

    /**
     * Run void.
     *
     * @param fromInclude the from include
     * @param toExclude   the to exclude
     * @param action      the action
     */
    public static void run(int fromInclude, int toExclude, final Action1<Integer> action) {
        int step = (fromInclude <= toExclude) ? 1 : -1;
        run(fromInclude, toExclude, step, action);
    }

    /**
     * Run void.
     *
     * @param fromInclude the from include
     * @param toExclude   the to exclude
     * @param step        the step
     * @param action      the action
     */
    public static void run(int fromInclude, int toExclude, int step, final Action1<Integer> action) {
        shouldNotBeNull(action, "function");

        if (log.isDebugEnabled())
            log.debug(
                    " ? ... fromInclude=[{}], toExclude=[{}], step=[{}], workerCount=[{}]",
                    fromInclude, toExclude, step, getWorkerCount());
        ExecutorService executor = Executors.newFixedThreadPool(getWorkerCount());

        try {
            List<NumberRange.IntRange> partitions = NumberRange.partition(fromInclude, toExclude, step,
                    getWorkerCount());
            List<Callable<Void>> tasks = Lists.newLinkedList();

            for (final NumberRange.IntRange partition : partitions) {
                Callable<Void> task = new Callable<Void>() {
                    @Override
                    public Void call() throws Exception {
                        for (final int element : partition)
                            action.perform(element);
                        return null;
                    }
                };
                tasks.add(task);
            }

            List<Future<Void>> results = executor.invokeAll(tasks);
            for (Future<Void> result : results) {
                result.get();
            }

            if (log.isDebugEnabled())
                log.debug(" ?  !");

        } catch (Exception e) {
            log.error("???      ?.", e);
            throw new RuntimeException(e);
        } finally {
            executor.shutdown();
        }
    }

    /**
     * Run list.
     *
     * @param count    the count
     * @param callable the callable
     * @return the list
     */
    public static <V> List<V> run(int count, final Callable<V> callable) {
        return run(0, count, callable);
    }

    /**
     * Run list.
     *
     * @param fromInclude the from include
     * @param toExclude   the to exclude
     * @param callable    the callable
     * @return the list
     */
    public static <V> List<V> run(int fromInclude, int toExclude, final Callable<V> callable) {
        int step = (fromInclude <= toExclude) ? 1 : -1;
        return run(fromInclude, toExclude, step, callable);
    }

    /**
     * Run list.
     *
     * @param fromInclude the from include
     * @param toExclude   the to exclude
     * @param step        the step
     * @param callable    the callable
     * @return the list
     */
    public static <V> List<V> run(int fromInclude, int toExclude, int step, final Callable<V> callable) {
        shouldNotBeNull(callable, "callable");
        if (isDebugEnabled)
            log.debug(
                    " ? ... fromInclude=[{}], toExclude=[{}], step=[{}], workerCount=[{}]",
                    fromInclude, toExclude, step, getWorkerCount());

        ExecutorService executor = Executors.newFixedThreadPool(getWorkerCount());

        try {
            List<NumberRange.IntRange> partitions = NumberRange.partition(fromInclude, toExclude, step,
                    getWorkerCount());
            final Map<Integer, List<V>> localResults = Maps.newLinkedHashMap();
            List<Callable<List<V>>> tasks = Lists.newLinkedList(); // False Sharing?  

            for (int p = 0; p < partitions.size(); p++) {
                final NumberRange.IntRange partition = partitions.get(p);
                final List<V> localResult = Lists.newArrayListWithCapacity(partition.size());
                localResults.put(p, localResult);

                Callable<List<V>> task = new Callable<List<V>>() {
                    @Override
                    public List<V> call() throws Exception {
                        for (final int element : partition)
                            localResult.add(callable.call());
                        return localResult;
                    }
                };
                tasks.add(task);
            }

            executor.invokeAll(tasks);

            List<V> results = Lists.newCopyOnWriteArrayList();
            for (int i = 0; i < partitions.size(); i++) {
                results.addAll(localResults.get(i));
            }

            if (isDebugEnabled)
                log.debug(" ?  . workerCount=[{}]", getWorkerCount());

            return results;
        } catch (Exception e) {
            log.error("???      ?.", e);
            throw new RuntimeException(e);
        } finally {
            executor.shutdown();
        }
    }

    /**
     * Run list.
     *
     * @param count    the count
     * @param function the function
     * @return the list
     */
    public static <V> List<V> run(int count, final Function1<Integer, V> function) {
        return run(0, count, function);
    }

    /**
     *  ?  .
     *
     * @param fromInclude  ?? ()
     * @param toExclude    ?? (?)
     * @param function    the function
     * @return   
     */
    public static <V> List<V> run(int fromInclude, int toExclude, final Function1<Integer, V> function) {
        int step = (fromInclude <= toExclude) ? 1 : -1;
        return run(fromInclude, toExclude, step, function);
    }

    /**
     *  ?  .
     *
     * @param fromInclude  ?? ()
     * @param toExclude    ?? (?)
     * @param step        Step
     * @param function     
     * @return   
     */
    public static <V> List<V> run(int fromInclude, int toExclude, int step, final Function1<Integer, V> function) {
        shouldNotBeNull(function, "function");
        if (isDebugEnabled)
            log.debug(
                    " ? ... fromInclude=[{}], toExclude=[{}], step=[{}], workerCount=[{}]",
                    fromInclude, toExclude, step, getWorkerCount());

        ExecutorService executor = Executors.newFixedThreadPool(getWorkerCount());

        try {
            List<NumberRange.IntRange> partitions = NumberRange.partition(fromInclude, toExclude, step,
                    getWorkerCount());
            final Map<Integer, List<V>> localResults = Maps.newLinkedHashMap();
            List<Callable<List<V>>> tasks = Lists.newLinkedList(); // False Sharing?  

            for (int p = 0; p < partitions.size(); p++) {
                final NumberRange.IntRange partition = partitions.get(p);
                final List<V> localResult = Lists.newArrayListWithCapacity(partition.size());
                localResults.put(p, localResult);

                Callable<List<V>> task = new Callable<List<V>>() {
                    @Override
                    public List<V> call() throws Exception {
                        for (final int element : partition)
                            localResult.add(function.execute(element));
                        return localResult;
                    }
                };
                tasks.add(task);
            }

            executor.invokeAll(tasks);

            List<V> results = Lists.newArrayList();
            for (int i = 0; i < partitions.size(); i++) {
                results.addAll(localResults.get(i));
            }
            if (isDebugEnabled)
                log.debug(" ?  . workerCount=[{}]", getWorkerCount());

            return results;
        } catch (Exception e) {
            log.error("???      ?.", e);
            throw new RuntimeException(e);
        } finally {
            executor.shutdown();
        }
    }

    /**
     *  ? ,  ? ? .
     *
     * @param elements action?  ??  
     * @param action    function
     */
    public static <T> void runEach(final Iterable<T> elements, final Action1<T> action) {
        shouldNotBeNull(elements, "elements");
        shouldNotBeNull(action, "function");
        if (isDebugEnabled)
            log.debug(" ? ... workerCount=[{}]", getWorkerCount());

        ExecutorService executor = Executors.newFixedThreadPool(getWorkerCount());

        try {
            List<T> elemList = Lists.newArrayList(elements);
            int partitionSize = getPartitionSize(elemList.size(), getWorkerCount());
            Iterable<List<T>> partitions = Iterables.partition(elemList, partitionSize);
            List<Callable<Void>> tasks = Lists.newLinkedList();

            for (final List<T> partition : partitions) {
                Callable<Void> task = new Callable<Void>() {
                    @Override
                    public Void call() throws Exception {
                        for (final T element : partition)
                            action.perform(element);
                        return null;
                    }
                };
                tasks.add(task);
            }
            List<Future<Void>> results = executor.invokeAll(tasks);
            for (Future<Void> result : results) {
                result.get();
            }

            if (isDebugEnabled)
                log.debug(" ?  . workerCount=[{}]", getWorkerCount());

        } catch (Exception e) {
            log.error("???      ?.", e);
            throw new RuntimeException(e);
        } finally {
            executor.shutdown();
        }
    }

    /**
     *  ? ,  function? ,  .
     *
     * @param elements function?  
     * @param function  
     * @return  ? 
     */
    public static <T, V> List<V> runEach(final Iterable<T> elements, final Function1<T, V> function) {
        shouldNotBeNull(elements, "elements");
        shouldNotBeNull(function, "function");
        if (isDebugEnabled)
            log.debug(" ? ... workerCount=[{}]", getWorkerCount());

        ExecutorService executor = Executors.newFixedThreadPool(getWorkerCount());

        try {
            List<T> elemList = Lists.newArrayList(elements);
            int partitionSize = getPartitionSize(elemList.size(), getWorkerCount());
            List<List<T>> partitions = Lists.partition(elemList, partitionSize);
            final Map<Integer, List<V>> localResults = Maps.newLinkedHashMap();

            List<Callable<List<V>>> tasks = Lists.newLinkedList(); // False Sharing?  

            for (int p = 0; p < partitions.size(); p++) {
                final List<T> partition = partitions.get(p);
                final List<V> localResult = Lists.newArrayListWithCapacity(partition.size());
                localResults.put(p, localResult);

                Callable<List<V>> task = new Callable<List<V>>() {
                    @Override
                    public List<V> call() throws Exception {
                        for (final T element : partition)
                            localResult.add(function.execute(element));
                        return localResult;
                    }
                };
                tasks.add(task);
            }

            executor.invokeAll(tasks);

            List<V> results = Lists.newArrayListWithCapacity(elemList.size());

            for (int i = 0; i < partitions.size(); i++) {
                results.addAll(localResults.get(i));
            }

            if (isDebugEnabled)
                log.debug(" ?  . workerCount=[{}]", getWorkerCount());

            return results;

        } catch (Exception e) {
            log.error("???      ?.", e);
            throw new RuntimeException(e);
        } finally {
            executor.shutdown();
        }
    }

    /**
     *  ?  .
     *
     * @param count   
     * @param action  
     */
    public static void runPartitions(int count, final Action1<List<Integer>> action) {
        runPartitions(0, count, action);
    }

    /**
     *  ?  .
     *
     * @param fromInclude  ?? ()
     * @param toExclude    ?? (?)
     * @param action       
     */
    public static void runPartitions(int fromInclude, int toExclude, final Action1<List<Integer>> action) {
        int step = (fromInclude <= toExclude) ? 1 : -1;
        runPartitions(fromInclude, toExclude, step, action);
    }

    /**
     *  ?  .
     *
     * @param fromInclude  ?? ()
     * @param toExclude    ?? (?)
     * @param step        Step
     * @param action       
     */
    public static void runPartitions(int fromInclude, int toExclude, int step,
            final Action1<List<Integer>> action) {
        shouldNotBeNull(action, "function");
        if (isDebugEnabled)
            log.debug(
                    " ? ... fromInclude=[{}], toExclude=[{}], step=[{}], workerCount=[{}]",
                    fromInclude, toExclude, step, getWorkerCount());

        ExecutorService executor = Executors.newFixedThreadPool(getWorkerCount());

        try {
            List<NumberRange.IntRange> partitions = NumberRange.partition(fromInclude, toExclude, step,
                    getWorkerCount());
            List<Callable<Void>> tasks = Lists.newLinkedList();

            for (NumberRange.IntRange partition : partitions) {
                final List<Integer> inputs = Lists.newArrayList(partition.iterator());
                Callable<Void> task = new Callable<Void>() {
                    @Override
                    public Void call() throws Exception {
                        action.perform(inputs);
                        return null;
                    }
                };
                tasks.add(task);
            }

            List<Future<Void>> results = executor.invokeAll(tasks);
            for (Future<Void> result : results) {
                result.get();
            }

            if (log.isDebugEnabled())
                log.debug(" ?  !");

        } catch (Exception e) {
            log.error("???      ?.", e);
            throw new RuntimeException(e);
        } finally {
            executor.shutdown();
        }
    }

    /**
     *  ?  .
     *
     * @param count     
     * @param function  
     * @return   
     */
    public static <V> List<V> runPartitions(int count, final Function1<List<Integer>, List<V>> function) {
        return runPartitions(0, count, function);
    }

    /**
     *  ?  .
     *
     * @param fromInclude  ?? ()
     * @param toExclude    ?? (?)
     * @param function     
     * @return   
     */
    public static <V> List<V> runPartitions(int fromInclude, int toExclude,
            final Function1<List<Integer>, List<V>> function) {
        int step = (fromInclude <= toExclude) ? 1 : -1;
        return runPartitions(fromInclude, toExclude, step, function);
    }

    /**
     *  ?  .
     *
     * @param fromInclude  ?? ()
     * @param toExclude    ?? (?)
     * @param step        Step
     * @param function     
     * @return   
     */
    public static <V> List<V> runPartitions(int fromInclude, int toExclude, int step,
            final Function1<List<Integer>, List<V>> function) {
        shouldNotBeNull(function, "function");
        if (isDebugEnabled)
            log.debug(
                    " ? ... fromInclude=[{}], toExclude=[{}], step=[{}], workerCount=[{}]",
                    fromInclude, toExclude, step, getWorkerCount());

        ExecutorService executor = Executors.newFixedThreadPool(getWorkerCount());

        try {
            List<NumberRange.IntRange> partitions = NumberRange.partition(fromInclude, toExclude, step,
                    getWorkerCount());
            List<Callable<List<V>>> tasks = Lists.newLinkedList(); // False Sharing?  

            for (final NumberRange.IntRange partition : partitions) {
                final List<Integer> inputs = Lists.newArrayList(partition.iterator());
                Callable<List<V>> task = new Callable<List<V>>() {
                    @Override
                    public List<V> call() throws Exception {
                        return function.execute(inputs);
                    }
                };
                tasks.add(task);
            }
            //  
            List<Future<List<V>>> outputs = executor.invokeAll(tasks);

            List<V> results = Lists.newArrayList();
            for (Future<List<V>> output : outputs) {
                results.addAll(output.get());
            }

            if (isDebugEnabled)
                log.debug(" ?  . workerCount=[{}]", getWorkerCount());

            return results;

        } catch (Exception e) {
            log.error("???      ?.", e);
            throw new RuntimeException(e);
        } finally {
            executor.shutdown();
        }
    }

    /**
     *  ? ,  ? .
     *
     * @param elements  ??
     * @param action    
     */
    public static <T> void runPartitions(final Iterable<T> elements, final Action1<List<T>> action) {
        shouldNotBeNull(elements, "elements");
        shouldNotBeNull(action, "function");
        if (isDebugEnabled)
            log.debug(" ? ... workerCount=[{}]", getWorkerCount());

        ExecutorService executor = Executors.newFixedThreadPool(getWorkerCount());

        try {
            List<T> elemList = Lists.newArrayList(elements);
            int partitionSize = getPartitionSize(elemList.size(), getWorkerCount());
            Iterable<List<T>> partitions = Iterables.partition(elemList, partitionSize);
            List<Callable<Void>> tasks = Lists.newLinkedList();

            for (final List<T> partition : partitions) {
                Callable<Void> task = new Callable<Void>() {
                    @Override
                    public Void call() throws Exception {
                        action.perform(partition);
                        return null;
                    }
                };
                tasks.add(task);
            }
            //  
            List<Future<Void>> results = executor.invokeAll(tasks);

            for (Future<Void> result : results)
                result.get();

            if (isDebugEnabled)
                log.debug(" ?  . workCount=[{}]");
        } catch (Exception e) {
            log.error("???    ?.", e);
            throw new RuntimeException(e);
        } finally {
            executor.shutdown();
        }
    }

    /**
     *  ? ,  ? .
     *
     * @param elements  ??
     * @param function  
     * @return  
     */
    public static <T, V> List<V> runPartitions(final Iterable<T> elements,
            final Function1<List<T>, List<V>> function) {
        shouldNotBeNull(elements, "elements");
        shouldNotBeNull(function, "function");
        if (isDebugEnabled)
            log.debug(" ? ... workerCount=[{}]", getWorkerCount());

        ExecutorService executor = Executors.newFixedThreadPool(getWorkerCount());

        try {
            List<T> elemList = Lists.newArrayList(elements);
            int partitionSize = getPartitionSize(elemList.size(), getWorkerCount());
            List<List<T>> partitions = Lists.partition(elemList, partitionSize);
            final Map<Integer, List<V>> localResults = Maps.newLinkedHashMap();

            List<Callable<List<V>>> tasks = Lists.newLinkedList(); // False Sharing?  

            for (final List<T> partition : partitions) {
                Callable<List<V>> task = new Callable<List<V>>() {
                    @Override
                    public List<V> call() throws Exception {
                        return function.execute(partition);
                    }
                };
                tasks.add(task);
            }
            //  
            List<Future<List<V>>> futures = executor.invokeAll(tasks);

            List<V> results = Lists.newArrayListWithCapacity(elemList.size());
            for (Future<List<V>> future : futures)
                results.addAll(future.get());

            if (isDebugEnabled)
                log.debug(" ?  . workerCount=[{}]", getWorkerCount());

            return results;

        } catch (Exception e) {
            log.error("???      ?.", e);
            throw new RuntimeException(e);
        } finally {
            executor.shutdown();
        }
    }

}