2016-09-11 4 views
3

Как я могу повторно использовать в java8 (возможно, процесс memoization) значения, уже вычисленные с помощью итерации по потоку?поток Java8 с memoization

Если поток дублируется или поставляется снова, он будет пересчитан. В некоторых случаях было бы предпочтительнее торговать память за это время процессора. Сбор всего с самого начала может быть не очень хорошей идеей, так как поток используется для поиска первого элемента, который удовлетворяет предикату.

Stream<Integer> all = Stream.of(1,2,3,4,5, ...<many other values>...). 
     map(x->veryLongTimeToComputeFunction(x)); 
System.out.println("fast find of 2"+all.filter(x->x>1).findFirst()); 

//both of these two lines generate a "java.lang.IllegalStateException: stream has already been operated upon or closed" 
System.out.println("no find"+all.filter(x->x>10).findFirst()); 
System.out.println("find again"+all.filter(x->x>4).findFirst()); 

Вопрос заключается в том, чтобы Copy a stream to avoid "stream has already been operated upon or closed" (java 8) всего напоминает

ответ

0

Я хотел бы предложить собирать ваши Stream в список и затем запустить фильтры на поток списка.

+0

Но это будет выполнять veryLongTimeToComputeFunction для всех полей, в конце концов, чтобы сохранить первый. – raisercostin

1

Почему бы не использовать меморандум внутри veryLongTimeToComputeFunction? Вы можете поместить memo cache в качестве параметра в func.

0

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

public static void main(String[] args) { 
    Supplier<Stream<Integer>> s=memoize(
     IntStream.range(0, 10_000) 
       .map(x -> veryLongTimeToComputeFunction(x)) 
    ); 
    System.out.println("First item > 1 "+s.get().filter(x -> x>1).findFirst()); 
    System.out.println("First item > 10 "+s.get().filter(x -> x>10).findFirst()); 
    System.out.println("First item > 4 "+s.get().filter(x -> x>4).findFirst()); 
} 
static int veryLongTimeToComputeFunction(int arg) { 
    System.out.println("veryLongTimeToComputeFunction("+arg+")"); 
    return arg; 
} 

public static <T> Supplier<Stream<T>> memoize(BaseStream<T,?> stream) { 
    Spliterator<T> sp=stream.spliterator(); 
    class S extends Spliterators.AbstractSpliterator<T> { 
     ArrayList<T> mem=new ArrayList<>(); 
     S() { super(sp.estimateSize(), sp.characteristics()); } 
     public boolean tryAdvance(Consumer<? super T> action) { 
      int ix=mem.size(); 
      if(sp.tryAdvance(mem::add)) { 
       action.accept(mem.get(ix)); 
       return true; 
      } 
      return false; 
     } 
    } 
    S s=new S(); 
    return() -> Stream.concat(s.mem.stream(), StreamSupport.stream(s, false)); 
} 

Позаботьтесь, чтобы закончить обработку потока перед запросом следующего потока от поставщика.

+0

Спасибо. Я попробую, я надеялся найти что-то в коллекциях java или, по крайней мере, в guava, apache commons или в другой общедоступной небольшой библиотеке. – raisercostin

+0

Ну, вы можете поместить это в небольшую библиотеку ... – Holger

0

Потоки не должны быть сохранены, они находятся в состоянии процесс данные.

Пример: вы смотрите dvd, в java-терминах dvd будет чем-то вроде коллекции, данные, переданные с вашего dvd-плеера на ваш телевизор, являются потоком. Вы не можете сохранить поток, однако вы можете записать cd, в java-терминалах его собираете.

Есть и другие варианты:

  • экстракт/реорганизовать свои операции потока или предикаты к способу, который получает поток в качестве параметра и возвращает поток
  • использовать рамки кэширования: например, в методах Spring можно аннотировать @Cacheable. Первый вызов выполняет метод, последующие вызовы извлекают результаты из кэша для определенного времени
  • , если вы ищете неблокируемое выполнение для вас длинной выполняющейся задачи, взгляните на RxJava
+0

Если потоки java не предназначены для сохранения, какая будет коллекция, которая делает именно это? Потоки Scala делают это, не обращаясь к специализированным фреймворкам. – raisercostin

+0

@raisercostin, который представляет собой подход java о потоках. В потоках Java это только функциональное «дополнение», Scala было разработано как чисто функциональное. Во всяком случае, поскольку veryLongTimeToComputeFunction (x) настолько тяжел на процессоре, вы получите большую производительность, добавив в ваш поток «.parallel()». – Journeycorner

0

Java 8 потоков носят ленивый характер. Операции, выполняемые в потоках, оцениваются в вертикальном порядке. То, что вы хотите достичь может быть достигнута с помощью следующего кода:

Stream.of(1,2,3,4,5, ...<many other values>...) 
    .map(x-> veryLongTimeToComputeFunction(x)) 
    .filter(x-> x > 1) 
    .findFirst(); 

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

Также вы можете использовать параллельные потоки в сочетании с методом findAny(). Это ускорит работу.

 Смежные вопросы

  • Нет связанных вопросов^_^