Java: как масштабировать потоки в соответствии с ядрами процессора?


Я не хороший программист java, это просто мое хобби, но я хочу знать больше, чем средний материал.

Я хочу решить математическую задачу с несколькими потоками в Java. моя математическая задача может быть разделена на рабочие единицы, которые я хочу решить в нескольких потоках.

но я не хочу, чтобы на нем работало фиксированное количество потоков, а вместо этого количество потоков соответствовало количеству ядер процессора. и моя проблема в том, что я не мог найти легкий учебник в интернете для этого. все, что я нашел, это примеры с фиксированными потоками.

Так не могли бы вы помочь мне со ссылкой на хороший tuturial или может дать мне простой и хороший пример? Это было бы очень приятно:)

6 89

6 ответов:

вы можете определить количество процессов, доступных для виртуальной машины Java с помощью статического метода выполнения,availableProcessors. Как только вы определили количество доступных процессоров, создайте это количество потоков и разделите свою работу соответственно.

обновление: чтобы уточнить, поток-это просто объект в Java, поэтому вы можете создать его так же, как и любой другой объект. Итак, предположим, что вы называете выше метод и найти, что он возвращает 2 процессора. Потрясающий. Теперь вы можете создать цикл, который генерирует новый поток, и разбивает работу для этого потока, и запускает поток. Вот некоторые psuedocode, чтобы продемонстрировать, что я имею в виду:

int processors = Runtime.getRuntime().availableProcessors();
for(int i=0; i < processors; i++) {
  Thread yourThread = new AThreadYouCreated();
  // You may need to pass in parameters depending on what work you are doing and how you setup your thread.
  yourThread.start();
}

для получения дополнительной информации о создании собственного потока,перейти к этому учебнику. Кроме того, вы можете посмотреть на Пул Потоков для создания потоков.

вы, вероятно, хотите посмотреть на java.утиль.параллельные структуры для этого. Что-то вроде:

ExecutorService e = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
// Do work using something like either
e.execute(new Runnable() {
        public void run() {
            // do one task
        }
    });

или

    Future<String> future = pool.submit(new Callable<String>() {
        public String call() throws Exception {
            return null;
        }
    });
    future.get();  // Will block till result available

Это намного лучше, чем справляться с собственными пулами потоков и т. д.

Дуг Леа (автор параллельного пакета) имеет эту статью, которая может быть актуальной: http://gee.cs.oswego.edu/dl/papers/fj.pdf

платформа Fork Join была добавлена в Java SE 7. Ниже приведены еще несколько ссылок:

http://www.ibm.com/developerworks/java/library/j-jtp11137/index.html Статья Брайана Гетца

http://www.oracle.com/technetwork/articles/java/fork-join-422606.html

Вариант 1:

newWorkStealingPool С Executors

public static ExecutorService newWorkStealingPool()

создает пул рабочих потоков с использованием всех доступных процессоров в качестве целевого уровня параллелизма.

С помощью этого API вам не нужно передавать количество ядер в ExecutorService.

реализация этого API от grepcode

/**
     * Creates a work-stealing thread pool using all
     * {@link Runtime#availableProcessors available processors}
     * as its target parallelism level.
     * @return the newly created thread pool
     * @see #newWorkStealingPool(int)
     * @since 1.8
     */
    public static ExecutorService newWorkStealingPool() {
        return new ForkJoinPool
            (Runtime.getRuntime().availableProcessors(),
             ForkJoinPool.defaultForkJoinWorkerThreadFactory,
             null, true);
    }

2:

newFixedThreadPool API от Executors или other newXXX constructors, который возвращает ExecutorService

public static ExecutorService newFixedThreadPool(int nThreads)

заменить nThreads наRuntime.getRuntime().availableProcessors()

Вариант 3:

ThreadPoolExecutor

public ThreadPoolExecutor(int corePoolSize,
                      int maximumPoolSize,
                      long keepAliveTime,
                      TimeUnit unit,
                      BlockingQueue<Runnable> workQueue)

передать Runtime.getRuntime().availableProcessors() в качестве параметра maximumPoolSize.

в классе Runtime существует метод availableProcessors (). Вы можете использовать это, чтобы выяснить, сколько процессоров у вас есть. Поскольку ваша программа привязана к процессору, вы, вероятно, захотите иметь (не более) один поток на доступный процессор.

стандартный способ выполнения.getRuntime().availableProcessors() метод. На большинстве стандартных процессоров вы вернете оптимальное количество потоков (которое не является фактическим количеством ядер процессора) здесь. Поэтому это то, что вы ищете.

пример:

ExecutorService service = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

не забудьте закрыть Службу executor вот так (или ваша программа не выйдет):

service.shutdown();

здесь просто краткое описание того, как настроить будущий код MT (offtopic, for иллюстрация):

CompletionService<YourCallableImplementor> completionService = 
    new ExecutorCompletionService<YourCallableImplementor>(service);
    ArrayList<Future<YourCallableImplementor>> futures = new ArrayList<Future<YourCallableImplementor>>();
    for (String computeMe : elementsToCompute) {
        futures.add(completionService.submit(new YourCallableImplementor(computeMe)));
    }

затем вам нужно отслеживать, сколько результатов вы ожидаете, и получить их следующим образом:

try {
  int received = 0;
  while (received < elementsToCompute.size()) {
     Future<YourCallableImplementor> resultFuture = completionService.take(); 
     YourCallableImplementor result = resultFuture.get();
     received++; 
  }
} finally {
  service.shutdown();
}