Joining of CompletableFutures - java

I've been working with CompletableFuture lately, trying to parallelize long lasting IO operations. I have to wait for everything to complete before I return, so I've used both
CompletableFuture.allOf().join()
and
stream().map(CompletableFuture::join)
to enforce this. However, looking at the logs, I've had the impression that allOf().join is faster. I've played around with a test to see. The output in the end always show a higher time spent for stream join. One thing I've seen is that if I skip System.out.println() in CompleteableFuture.supplyAsync(), the difference is less.
A typical output from the test as it is below:
streamJoin: 3196 ms, allof: 3055 ms
Is allOf().join(), and collecting afterwards the fastest way, or is my test flawed?
package com.oyvind.completablefutures;
import org.junit.Test;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class CompletableFutureTest {
#Test
public void joinPerformanceTest() throws Exception{
// stream join
long startStreamJoin = System.currentTimeMillis();
List<Integer> result1 = listOfCompletableFutures("stream", Executors.newFixedThreadPool(100))
.stream()
.map(CompletableFuture::join)
.collect(Collectors.toList());// trigger execution
long spentTimeStreamJoin = System.currentTimeMillis() - startStreamJoin;
// allOf() join
long startAllOf = System.currentTimeMillis();
List<CompletableFuture<Integer>> completableFutures = listOfCompletableFutures("allOf", Executors.newFixedThreadPool(100));
CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0])).join();
List<Integer> result2 = completableFutures.stream().map(CompletableFuture::join).collect(Collectors.toList());
long spentTimeAllOf = System.currentTimeMillis() - startAllOf;
log("streamJoin: %s ms, allof: %s ms", spentTimeStreamJoin, spentTimeAllOf);
}
private List<CompletableFuture<Integer>> listOfCompletableFutures(String name, Executor executor) {
return IntStream.range(1, 1000)
.boxed()
.map(
i -> CompletableFuture.supplyAsync(
() -> logAndSleepFor1Second(name),
executor
)
)
.collect(Collectors.toList());
}
private int logAndSleepFor1Second(String name) {
log("Starting %s: %s", name, Thread.currentThread().getName());
try {
Thread.sleep(300);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return 1;
}
private void log(String format, Object... args) {
System.out.println(LocalDateTime.now() + ": " + String.format(format, args));
}
}

Related

Mono retry with backoff not getting called for few elements in stream

There are stream of integers that I am trying to process. Incase of an exception I want to retry with backoff and at the same time backpressure will also be applied on the stream. I see that for few elements retry is not getting called.
To reproduce execute the below code and you should see code will be waiting indefinitely because queue becomes full coz for few elements doFinally is not called. In this case we should see count as 2000 but it will be less.
import org.junit.Assert;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;
import reactor.util.retry.Retry;
import java.time.Duration;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
public class MonoRetryTest {
private static final Logger logger = LoggerFactory.getLogger(MonoRetryTest.class);
private static BlockingQueue blockingQueue = new LinkedBlockingDeque(30);
private static final List values = Collections.synchronizedList(new LinkedList<Integer>());
#Test(timeout = 30000)
public void testMonoRetryWithBackOff() {
Flux.range(0,2000)
.publishOn(Schedulers.parallel())
.flatMap(e -> monoUtil(e))
.blockLast();
int processedValues = values.size();
Assert.assertTrue("Signal not recieved for all elements", 2000 == processedValues);
}
private static Mono monoUtil(int val) {
return Mono.just(1)
.flatMap(e -> {
try {
blockingQueue.put(val);
} catch (InterruptedException interruptedException) {
interruptedException.printStackTrace();
}
return serviceCall(Mono.just(val));
})
.doFinally(e -> {
blockingQueue.remove(val);
values.add(val);
logger.info("Finally Called "+ val);
});
}
private static Mono serviceCall(Mono<Integer> responseMono) {
return responseMono
.map(response -> test(response))
.retryWhen(Retry.backoff(3, Duration.ofMillis(10)))
.onErrorReturn("Failed");
}
private static String test(Integer value) {
if(value%5 == 0) throw new RuntimeException("Runtime Exception");
return "Success";
}
}

Using Observable.interval to wait for remote data or timeout

I need to wait for a condition or timeout. I came up with the following approach, but there are too many things happening. How can i compress this.
import io.reactivex.Observable;
import java.util.concurrent.TimeUnit;
import io.reactivex.schedulers.Schedulers;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.ThreadLocalRandom;
public class Test{
public static void main(String[] args)throws InterruptedException{
AtomicBoolean toggle = new
java.util.concurrent.atomic.AtomicBoolean(true);
Observable.interval(0,50, TimeUnit.MILLISECONDS)
.takeWhile(l->l<(20000/50))
.takeWhile(l-> toggle.get())
.observeOn(Schedulers.io())
.map(l->{ return (l>ThreadLocalRandom.current()
.nextInt(5, 20 + 1))?true:false;})
// The above map will call a remote function to check for some condition
.observeOn(Schedulers.computation())
.filter(exist->exist)
//.takeWhile(exist->!exist)
.map(l->{toggle.set(false);return l;})
.map(l->{System.out.println("Called at "+l);return l;})
.blockingSubscribe();
}
}
Here is code. You can use firstElement to get the first item.
import io.reactivex.Observable;
import io.reactivex.schedulers.Schedulers;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
public class Q44234633 {
public static void main(String[] args) throws InterruptedException {
Observable.interval(50, TimeUnit.MILLISECONDS)
.takeWhile(l -> l < 400)
.observeOn(Schedulers.io())
.filter(l -> isConditionTrue(l))
.observeOn(Schedulers.computation())
.firstElement()
.doOnSuccess(System.out::println)
.isEmpty()
.filter(empty -> empty)
.doOnSuccess(b -> System.out.println("TimeOut"))
.blockingGet();
}
private static boolean isConditionTrue(long time) {
return time > ThreadLocalRandom.current().nextInt(5, 20 + 1);
}
}
There are also two tips for you.
You can use doOnNext rather than map if you actually don't map the value.
BooleanValue? true : false can be written BooleanValue directly.

creating dbthreadpools in java play

This is in relation to question in stackoverflow .
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
ExecutorService ec = Executors.newFixedThreadPool(100);
public CompletionStage<Result> test {
return CompletableFuture.supplyAsync(() -> {
return Ebean.createSqlQuery(sqlQuery).findList();
}, ec) // <-- 'ec' is the ExecutorService you want to use
.thenApply(rows -> {
ObjectMapper mapper = new ObjectMapper();
return ok(f(rows));
//do lot of computation over rows
)}
}
Does the program use default executioncontext to do the computation f(rows) or use the execution context ec?
If I want to set the settings similar to akka exection context like
my-context {
fork-join-executor {
parallelism-factor = 20.0
parallelism-max = 200
}
}
How do I do it?

Java SchedulerExecutor

Recently I wrote code that had to limit request throughput. I used ScheduleExecutorService.scheduleAtFixedRate and I believed that it should do the work (It did!) but I wrote some test to check time of scheduled task and i was amazed. First few tasks weren't scheduled as javadoc explain with n*period. Can anyone explain me what am I missing?
If it work that way then why it is not mentioned in javadoc? And then question is how exactly scheduler work?
I would like to avoid looking into sources:)
Example:
import java.time.Duration;
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ExecutorTest {
Executor executor;
ScheduledExecutorService schedulingExecutor;
BlockingQueue<LocalTime> times;
public static void main(String[] args) throws InterruptedException {
new ExecutorTest().start();
}
public ExecutorTest() {
schedulingExecutor = Executors.newScheduledThreadPool(1);
executor = Executors.newCachedThreadPool();
times = new LinkedBlockingQueue<>();
}
public void start() throws InterruptedException {
schedulingExecutor.scheduleAtFixedRate(this::executeTask, 0, 50, TimeUnit.MILLISECONDS);
LocalTime nextEvaluatedTime = times.take();
LocalTime time = nextEvaluatedTime;
while (true) {
System.out.println(String.format(String.join(" ", "recorded time: %d", "calculated proper time: %d", "diff: %d"),
time.toNanoOfDay(),
nextEvaluatedTime.toNanoOfDay(),
Duration.between(nextEvaluatedTime, time).toNanos()));
nextEvaluatedTime = time.plus(50, ChronoUnit.MILLIS);
time = times.take();
}
}
private void executeTask() {
executor.execute(() -> {
times.add(LocalTime.now());
});
}
}
If you run this program you could see that few first time wasn't recorded as expected. Why?

Timestamp, timers, time question

I've been Googling Java timestamps, timers, and anything to do with time and Java.
I just can't seem to get anything to work for me.
I need a timestamp to control a while loop like the pseudo-code below
while(true)
{
while(mytimer.millsecounds < amountOftimeIwantLoopToRunFor)
{
dostuff();
}
mytimer.rest();
}
Any ideas what data type I could use; I have tried Timestamp, but didn't seem to work.
Thanks
CiarĂ¡n
Do something like:
long maxduration = 10000; // 10 seconds.
long endtime = System.currentTimeMillis() + maxduration;
while (System.currentTimeMillis() < endtime) {
// ...
}
An (more advanced) alternative is using java.util.concurrent.ExecutorService. Here's an SSCCE:
package com.stackoverflow.q2303206;
import java.util.Arrays;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class Test {
public static void main(String... args) throws Exception {
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.invokeAll(Arrays.asList(new Task()), 10, TimeUnit.SECONDS); // Get 10 seconds time.
executor.shutdown();
}
}
class Task implements Callable<String> {
public String call() throws Exception {
while (true) {
// ...
}
return null;
}
}

Categories

Resources