Java - Язык:Как масштабировать потоки в соответствии с ядрами процессора?
-
22-09-2019 - |
Вопрос
Я не очень хороший java-программист, это просто мое хобби, но я горю желанием знать больше, чем обычные вещи.
Я хочу решить математическую задачу с несколькими потоками на Java.моя математическая задача может быть разделена на рабочие блоки, которые я хочу решить в нескольких потоках.
но я не хочу иметь фиксированное количество потоков, работающих над этим, а вместо этого количество потоков, соответствующее количеству ядер процессора.и моя проблема в том, что я не смог найти простой учебник в Интернете для этого.все, что я нашел, - это примеры с фиксированными потоками.
Итак, не могли бы вы помочь мне ссылкой на хорошее учебное пособие или привести простой и наглядный пример?Это было бы действительно здорово :)
Решение
Вы можете определить количество процессов, доступных виртуальной машине Java, используя статический метод времени выполнения, Доступные процессоры.После того как вы определили количество доступных процессоров, создайте это количество потоков и соответствующим образом разделите свою работу.
Обновить:Чтобы еще раз уточнить, Поток - это просто объект в Java, поэтому вы можете создать его точно так же, как вы бы создали любой другой объект.Итак, предположим, что вы вызываете описанный выше метод и обнаруживаете, что он возвращает 2 процессора.Потрясающе.Теперь вы можете создать цикл, который генерирует новый поток, разделяет работу для этого потока и запускает поток.Вот некоторый псевдокод, чтобы продемонстрировать, что я имею в виду:
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.util.concurrent framework для этого материала.Что - то вроде:
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 ( код 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:
Новый фиксированный пул потоков API из Executors
или other newXXX constructors
, который возвращает ExecutorService
public static ExecutorService newFixedThreadPool(int nThreads)
замените nThreads на Runtime.getRuntime().availableProcessors()
Вариант 3:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue)
пройти Runtime.getRuntime().availableProcessors()
в качестве параметра для maximumPoolSize
.
Стандартным способом является метод Runtime.getRuntime().Available Processors().На большинстве стандартных процессоров вы вернете здесь оптимальное количество потоков (которое не является фактическим количеством ядер процессора).Следовательно, это то, что вы ищете.
Пример:
ExecutorService service = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
НЕ забудьте закрыть службу исполнителя подобным образом (иначе ваша программа не завершится).:
service.shutdown();
Вот лишь краткое описание того, как настроить будущий MT-код (оффтопик, для иллюстрации):
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();
}
В классе Runtime существует метод, называемый Available Processors() .Вы можете использовать это, чтобы выяснить, сколько процессоров у вас есть.Поскольку ваша программа привязана к процессору, вы, вероятно, хотели бы иметь (не более) одного потока на доступный процессор.