-
Notifications
You must be signed in to change notification settings - Fork 136
Example : Selecting the fastest algorithm result
If we wanted to test the relative performance of algorithms that solve the same problem, we can setup multiple reactive dataflows, one for each algorithm and select the fastest.
E.g. To test relative retrieval of ArrayLists and LinkedLists. Retrieval for ArrayLists is O(1), and retrieval for LinkedLists is O(n). Retrieving an item in the 1000th position should be much faster using an ArrayList.
@Test
public void testFastest() throws InterruptedException, ExecutionException {
ArrayList<Integer> arrayList = new ArrayList<>();
LinkedList<Integer> linkedList = new LinkedList<>();
for(int i=0;i<1001;i++){
arrayList.add(i);
linkedList.add(i);
}
}
We use Lombok for this type of thing, as it makes creating Immutable classes very straightforward and greatly cuts down boilerplate code.
@Wither //adds 'withXXXX' methods that create a new instance with property XXXX changed
@Getter //adds Java Bean getXXXX methods
@AllArgsConstructor //adds a Constructor which accepts all fields
@Builder //adds a builder class for this class
static class Result{
private final String name;
private final int result;
private final long time;
}
The equivalent Java for this class is at the bottom of this example doc.
private int retrieval(List<Integer> list) {
return list.get(1000);
}
@Test
public void testFastest() throws InterruptedException, ExecutionException {
ArrayList<Integer> arrayList = new ArrayList<>();
LinkedList<Integer> linkedList = new LinkedList<>();
for(int i=0;i<1001;i++){
arrayList.add(i);
linkedList.add(i);
}
Result result = new SimpleReact()
.<Result> react( () -> Result.builder().name("approach1").result(retrieval(arrayList)).build(),
() -> Result.builder().name("approach2").result(retrieval(linkedList)).build())
}
@Test
public void testFastest() throws InterruptedException, ExecutionException {
ArrayList<Integer> arrayList = new ArrayList<>();
LinkedList<Integer> linkedList = new LinkedList<>();
for(int i=0;i<1001;i++){
arrayList.add(i);
linkedList.add(i);
}
SimpleTimer timer = new SimpleTimer();
Result result = new SimpleReact()
.<Result> react( () -> Result.builder().name("approach1").result(retrieval(arrayList)).build(),
() -> Result.builder().name("approach2").result(retrieval(linkedList)).build())
.then(it -> it.withTime(timer.getElapsedNanoseconds()))
}
@Test
public void testFastest() throws InterruptedException, ExecutionException {
ArrayList<Integer> arrayList = new ArrayList<>();
LinkedList<Integer> linkedList = new LinkedList<>();
for(int i=0;i<1001;i++){
arrayList.add(i);
linkedList.add(i);
}
SimpleTimer timer = new SimpleTimer();
Result result = new SimpleReact()
.<Result> react( () -> Result.builder().name("approach1").result(retrieval(arrayList)).build(),
() -> Result.builder().name("approach2").result(retrieval(linkedList)).build())
.then(it -> it.withTime(timer.getElapsedNanoseconds()))
.filter(it -> it.getResult()==1000
}
@Test
public void testFastest() throws InterruptedException, ExecutionException {
ArrayList<Integer> arrayList = new ArrayList<>();
LinkedList<Integer> linkedList = new LinkedList<>();
for(int i=0;i<1001;i++){
arrayList.add(i);
linkedList.add(i);
}
SimpleTimer timer = new SimpleTimer();
Result result = new SimpleReact()
.<Result> react( () -> Result.builder().name("approach1").result(retrieval(arrayList)).build(),
() -> Result.builder().name("approach2").result(retrieval(linkedList)).build())
.then(it -> it.withTime(timer.getElapsedNanoseconds()))
.filter(it -> it.getResult()==1000)
.blockAndExtract(Extractors.first());
assertThat(result.getName(),is("approach1"));
}
approach1 : ArrayList retrieval should be the fastest and first to respond.
We are only interested in the first result back, so we don't need to block the current thread until both results are returned. We can supply a predicate to the blockAndExtract method that unblocks when a result is returned
e.g. status -> status.getCompleted() > 1
And the whole code
@Test public void testFastestLessBlocking() throws InterruptedException, ExecutionException {
ArrayList<Integer> arrayList = new ArrayList<>();
LinkedList<Integer> linkedList = new LinkedList<>();
for(int i=0;i<1001;i++){
arrayList.add(i);
linkedList.add(i);
}
SimpleTimer timer = new SimpleTimer();
Result result = new SimpleReact()
.<Result> react( () -> Result.builder().name("approach1 : arrayList").result(retrieval(arrayList)).build(),
() -> Result.builder().name("approach2 : linkedList").result(retrieval(linkedList)).build())
.then(it -> it.withTime(timer.getElapsedNanoseconds()))
.filter(it -> it.getResult()==1000)
.blockAndExtract(Extractors.first(),status -> status.getCompleted() > 0);
}
We can replace .blockAndExtract(Extractors.first(),status -> status.getCompleted() > 0) with the equivalent but neater first() method
.blockAndExtract(Extractors.first(),status -> status.getCompleted() > 0);
can be replaced with
.first()
And the whole code
@Test
public void testFastestLessBlocking() throws InterruptedException, ExecutionException {
ArrayList<Integer> arrayList = new ArrayList<>();
LinkedList<Integer> linkedList = new LinkedList<>();
for(int i=0;i<1001;i++){
arrayList.add(i);
linkedList.add(i);
}
SimpleTimer timer = new SimpleTimer();
Result result = new SimpleReact()
.<Result> react( () -> Result.builder().name("approach1 : arrayList").result(retrieval(arrayList)).build(),
() -> Result.builder().name("approach2 : linkedList").result(retrieval(linkedList)).build())
.then(it -> it.withTime(timer.getElapsedNanoseconds()))
.filter(it -> it.getResult()==1000)
.first();
assertThat(result.getName(),is("approach1 : arrayList"));
}
@Wither
@Getter
@AllArgsConstructor
@Builder
static class Result{
private final String name;
private final int result;
private final long time;
}
@Wither
@Getter
@AllArgsConstructor
@Builder
static class Result{
private final String name;
private final int result;
private final long time;
}
static class JavaResult {
private final String name;
private final int result;
private final long time;
public JavaResult(String name, int result, long time) {
super();
this.name = name;
this.result = result;
this.time = time;
}
static class Builder{
private String name;
private int result;
private long time;
public Builder name(String name){
this.name = name;
return this;
}
public Builder time(long time){
this.time = time;
return this;
}
public Builder result(int result){
this.result = result;
return this;
}
public JavaResult build(){
return new JavaResult(name,result,time);
}
}
public String getName() {
return name;
}
public int getResult() {
return result;
}
public long getTime() {
return time;
}
public JavaResult withName(String name) {
return new JavaResult.Builder().name(name).result(result).time(time).build();
}
public JavaResult withResult(int result) {
return new JavaResult.Builder().name(name).result(result).time(time).build();
}
public JavaResult getTime(long time) {
return new JavaResult.Builder().name(name).result(result).time(time).build();
}
}
oops - my bad