Чтобы упростить мой случай, предположим, что я реализую двоичный поиск с использованием инфраструктуры виджета Java. Моя цель - найти определенное целочисленное значение (целевое целое число) в массиве целых чисел. Это можно сделать, разбив массив на половину, пока он не станет достаточно маленьким, чтобы выполнить серийный поиск. Результатом алгоритма должно быть логическое значение, указывающее, было ли целевое целое найдено в массиве или нет.Добавление условия остановки к рекурсии fork-join
Аналогичная проблема исследуется в Klaus Kreft's presentation в слайде 28 дальше. Однако целью Kreft является найти наибольшее количество в массиве, поэтому все записи должны быть отсканированы. В моем случае нет необходимости сканировать полный массив, поскольку, как только целевое целое было найдено, поиск можно остановить.
Моя проблема в том, что как только я столкнулся с целым целым числом, многие задачи уже вставлены в пул потоков, и мне нужно их отменить, так как нет смысла продолжать поиск. Я попытался вызвать getPool(). Terminate() изнутри RecursiveTask, но это не помогло, поскольку многие задачи уже поставлены в очередь, и я даже заметил, что новые onces также поставлены в очередь даже после выключения.
My текущее решение - использовать статическое volatile boolean, которое инициируется как «false» и проверять его значение в начале задачи. Если он все еще «ложный», тогда задача начинает свои работы, если это «истина», задача немедленно возвращается. На самом деле я могу использовать для этого рекурсивную атаку.
Поэтому я думаю, что это решение должно работать, но мне интересно, предлагает ли структура стандартный способ обработки таких случаев - то есть определение условия остановки для рекурсии, которая, следовательно, отменяет все задачи в очереди.
Обратите внимание, что если я хочу немедленно остановить все запущенные задачи, когда целевое целое найдено (по одной из запущенных задач), я должен проверить логическое значение после каждой строки в этих задачах и это может повлиять на производительность, поскольку значение что boolean не может быть кэширован (он определяется как изменчивый).
Так что, действительно, я думаю, что требуется некоторое стандартное решение и может быть предоставлено в виде очистки очереди и перехвата выполняемых задач. Но я не нашел такого решения, и мне интересно, знает ли кто-нибудь еще об этом или имеет лучшую идею.
Спасибо за ваше время, Ассаф
EDIT: Вот мой код тестирования:
package xxx;
import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;
public class ForkJoinTest {
static final int ARRAY_SIZE = 1000;
static final int THRESHOLD = 10;
static final int MIN_VALUE = 0;
static final int MAX_VALUE = 100;
static Random rand = new Random();
// a function for retrieving a random int in a specific range
public static int randInt(int min, int max) {
return rand.nextInt((max - min) + 1) + min;
}
static volatile boolean result = false;
static int[] array = new int[ARRAY_SIZE];
static int target;
@SuppressWarnings("serial")
static class MyAction extends RecursiveAction {
int startIndex, endIndex;
public MyAction(int startIndex, int endIndex) {
this.startIndex = startIndex;
this.endIndex = endIndex;
}
// if the target integer was not found yet: we first check whether
// the entries to search are too few. In that case, we perform a
// sequential search and update the result if the target was found.
// Otherwise, we break the search into two parts and invoke the
// search in these two tasks.
@Override
protected void compute() {
if (!result) {
if (endIndex-startIndex<THRESHOLD) {
//
for (int i=startIndex ; i<endIndex ; i++) {
if (array[i]==target) {
result = true;
}
}
} else {
int middleIndex = (startIndex + endIndex)/2;
RecursiveAction action1 = new MyAction(startIndex, middleIndex);
RecursiveAction action2 = new MyAction(middleIndex+1, endIndex);
invokeAll(Arrays.asList(action1,action2));
}
}
}
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
for (int i=0 ; i<ARRAY_SIZE ; i++) {
array[i] = randInt(MIN_VALUE, MAX_VALUE);
}
target = randInt(MIN_VALUE, MAX_VALUE);
ForkJoinPool pool = new ForkJoinPool();
pool.invoke(new MyAction(0,ARRAY_SIZE));
System.out.println(result);
}
}
Можете ли вы разместить код? Вы можете использовать определенную очередь, которую вы можете очистить, и, возможно, прервать выполняемые потоки, но просмотр кода проще дать вам правильные предложения. –
Я поддерживаю фреймворк fork/join с открытым исходным кодом, который обеспечивает параллельный последовательный поиск, который обрабатывает вашу потребность в «поиске первой». Вы можете использовать его как есть или использовать код в качестве примера того, как сделать это самостоятельно. Ссылка sourceForge: http://sourceforge.net/projects/tymeacdse/?source=navbar – edharned
Спасибо @edharned, я посмотрю. Это зависит от платформы fork/join от Java? Вы также используете volatile boolean/AtomicBoolean, чтобы остановить поиск? – Assaf