Releases: aol/cyclops
v0.96
New in simple-react v0.96
Performance enhancements
New wait free Queue with mechanical sympathy
0.96 of simple-react adds support for simple-react Queue’s backed by a ManyToOneConcurrentArrayQueue.This is a Java implementation of an algorithm from Fast Flow, by the leading Java experts in this area (Martin Thompson, Richard Warburton, Todd Montgomery) via their Agrona project (which provides data structures and utilities used in the ultra-low-latency Aeron messaging system.
Performance characteristics
In simple benchmarking, LazyFutureStreams backed by an Agrona ManyToOneConcurrentArrayQueue can perform up to 40% faster than LazyFutureStreams backed by a JDK bounded wait free Queue (ConcurrentLinkedQueue). While results for most queue types showed significant variation in performance, throughput from LazyFutureStreams that are backed by Agrona ManyToOneConcurrentArrayQueue’s were much more stable. Differences in performance for LazyFutureStreams backed by ManyToOneConcurrentArrayQueue and ConcurrentLinkedQueue varied between 0 and over 40%. Non-blocking Queues performed up to twice as well as blocking queues (also with a lot of variation).
Bound size matters
Creating a bounded queue with a large buffer capacity can be expensive. Agrona ManyToOneConcurrentArrayQueue’s with a bound size of 200,000 entries were ~10 times slower than Agrona ManyToOneConcurrentArrayQueue’s with a bound size of 110.
JDK ConcurrentLinkedQueue is the default
Despite the improvements apparent from using the Agrona ManyToOneConcurrentArrayQueue as the backing Queue, we continue to use JDK ConcurrentLinkedQueue as the default. This is because it is impossible to tell what the bound size should be for all operations. For many / most operations, the bound size can be very similar to the concurrency level as determined by the MaxActive settings. But for other operators such as flatMap, it isn’t possible to tell how many elements would need to be buffered on the queue. For that reason, the backing queue is configurable per stage via two simple operators.
Non-blocking Queue operators
boundedWaitFree(int size)
This operator tells LazyFutureStream to use a bounded wait free queue for the subsequent stages (until configured otherwise). E.g.
new LazyReact(10,100) //configure a LazyFutureStream builder with a thread pool of 10 threads, that accepts 100 concurrent tasks
.react(toMyData) //define the initial Suppliers to asynchronously react to
.boundedWaitFree(110) //use a bounded queue factory, with max queue size slightly above the max number of concurrent tasks
.limit(400) //take the first 400 elements from this async Stream. The limit operator makes use of an async Queue and can thus benefit from being backed by an Agrona wait free queue.
.toList();
unboundedWaitFree()
This is the default operator and it tells LazyFutureStream to use an unbounded wait free Queue. Although algorithmically wait-free this Queue is more likely to experience contention at lower levels (e.g. via garbage collector activity, or invalidation of CPU caches), it is however, unbounded and as such
- does not incur significant queue creation costs
- less likely to cause data loss should flatMap based expansions turn out to be large.
new LazyReact(10,100) //configure a LazyFutureStream builder with a thread pool of 10 threads, that accepts 100 concurrent tasks
.react(toMyData) //define the initial Suppliers to asynchronously react to
.boundedWaitFree(110) //use a bounded queue factory, with max queue size slightly above the max number of concurrent tasks
.limit(400) //take the first 400 elements from this async Stream. The limit operator makes use of an async Queue and can thus benefit from being backed by an Agrona wait free queue.
.unboundedWaitFree() //switch to unboundedWaitFree before performing an large flatMap operation
.flatMap(this::loadAndStream)
.toList();
Recommendations
Use a boundedWaitFree queue where bound sizes can be reasonably asserted to be low, otherwise favor an unbounded wait free queue. Test, test, test your assumptions on performance critical paths.
What do we mean backed by a Queue?
simple-react works by perforrming aggregate operations over Streams of CompletableFutures. To perform more complex operations we often need the result that will be asynchronously populated in the Future. In order to keep data flowing smoothly through your Stream, we ‘plumb’ multiple different streams together internally, asynchronously populatng and extracting data from simple-react async.Queues. While the simple-react async.Queue provides the necessary logic to manage this, it isn’t in itself an actual Queue data structure implementation. The backing Queue is pluggable, and simple-react QueueFactories are provided for a range of blocking and non-blocking queue implementations.
Adding simple-react as a Dependency
Gradle
compile group: 'com.aol.simplereact', name:'simple-react', version:'0.96’
Maven
<dependency>
<groupId>com.aol.simplereact</groupId>
<artifactId>simple-react</artifactId>
<version>0.96</version>
<scope>compile</scope>
</dependency>
Javadoc
http://www.javadoc.io/doc/com.aol.simplereact/simple-react/0.96
v.095 of simple-react
New in simple-react v0.95
LazyFutureStream enhancements
Backed by a non-blocking wait free queue by default
Incremental Parallel Reduction
Collect /forEach / reduce all start fully asyncrhonous & parallel LazyFutureStreams in the same manner as Run (previously they would only allow one active chain of Futures at a time)
Interface enhancements
Creational methods following naming convention
of : data for immediate consumption
react : data for asynchronous consumption
List<Data> result = LazyFutureStream.of(1,2,3,4)
.map(this:process)
.run(Collectors.toList());
List<Data> result = EagerFutureStream.react(this::loadData1,this::loadData2,this::loadData3)
.map(this:process)
.toList();
Interface clean up
We are approaching the 1.0.0 release, and the interface will be more stable in the future. Dropped in this release where the simple-react generators and react collectors. Naming of creational methods was cleaned up to follow a pattern (see above).
General enhancements
Lombok removed as an runtime dependency
Guava replaced with lighterweight pcollections (simple-react-0.95-all.jar is ~400k)
Accept Executor rather than ExecutorService
Cyclops Monad comprehenders for use with Cyclops for comprehensions and Monad wrapper
Adding simple-react as a Dependency
Gradle
compile group: 'com.aol.simplereact', name:'simple-react', version:'0.95'
Maven
<dependency>
<groupId>com.aol.simplereact</groupId>
<artifactId>simple-react</artifactId>
<version>0.95</version>
<scope>compile</scope>
</dependency>
Javadoc
http://www.javadoc.io/doc/com.aol.simplereact/simple-react/0.95
v0.86 of simple-react
New in simple-react v0.86
Fix for #28
Adding simple-react as a Dependency
Gradle
compile group: 'com.aol.simplereact', name:'simple-react', version:'0.86'
Maven
<dependency>
<groupId>com.aol.simplereact</groupId>
<artifactId>simple-react</artifactId>
<version>0.86</version>
<scope>compile</scope>
</dependency>
Javadoc
http://www.javadoc.io/doc/com.aol.simplereact/simple-react/0.86
v0.85 simple-react : minor api clean up
New in simple-react v0.85
Minor API changes
Eager / Lazy static builder methods have been removed from EagerFutureStream, SimpleReactStream and LazyFutureStream.
EagerReact / LazyReact / SimpleReact .construct method has been cleaned up
Adding SimpleReact as a Dependency
Gradle
compile group: 'com.aol.simplereact', name:'simple-react', version:'0.85'
Maven
<dependency>
<groupId>com.aol.simplereact</groupId>
<artifactId>simple-react</artifactId>
<version>0.85</version>
<scope>compile</scope>
</dependency>
Javadoc
http://www.javadoc.io/doc/com.aol.simplereact/simple-react/0.85
v0.84 simple-react : Performance enhancements
New in simple-react v0.84
Performance enhancements
- run operator for LazyFurtureStream uses CompletableFutures.anyOf rather than spin locking
- new operators sync() and async()
- new operators thenSync, peekSync, filterSync, doOnEachSync
Interface clean up
SimpleReact builder no longer supports lazy operation, use LazyReact / LazyFutureStream instead
async() and sync() operators
async() and sync() can used to determine if subsequent tasks should be executed on the same thread as the completing task, or if they should be resubmitted to an Executor Service where they may be executed on a different thread. If async() is used the next tasks will be resubmitted for execution, if sync() is used the next tasks will be executed on the same thread as the completing task.
On a quad-core Mac Book Pro it is possible to do around ~335 million map operations per second in sync mode versus ~33 million in async mode. Use async to distribute work across threads (or for blocking operations) and sync to continue working efficiently on the completing thread.
A mix of async and sync execution. There is a performance overhead of submitting tasks to an ExecutorService - for non-blocking fast running code this should be avoided where possible.
Typical aysnc execution where each completed task, triggers another task which submitted to an ExecutorService for execution.
Adding SimpleReact as a Dependency
Gradle
compile group: 'com.aol.simplereact', name:'simple-react', version:'0.84'
Maven
<dependency>
<groupId>com.aol.simplereact</groupId>
<artifactId>simple-react</artifactId>
<version>0.84</version>
<scope>compile</scope>
</dependency>
Javadoc
http://www.javadoc.io/doc/com.aol.simplereact/simple-react/0.84
v0.83 : PushableStreamBuilder
New in simple-react v0.83
v0.83 introduces the PushableStreamBuilder, a builder for building Java 8 Streams or LazyFutureStreams that can accept external data being pushed in.
Java 8 Streams operate under a pull model, pulling data along the Stream. simple-react Streams such as LazyFutureStream, EagerFutureStream and SimpleReactStream operate under a mixed pull / push model. See simple-react pull/push model for more details.
With simple-react async data structures both types of Streams (and jool Seqs) can be used on a push basis.
(simple-react pull/push model)
simple-react Stream accepting pushed data from an async.Queue.
Stream creation examples
Creating a Java 8 Stream from an async.Queue can be as simple as
Queue<String> queue = QueueFactories.<String>unboundedQueue().build();
queue.stream();
The PushableStreamBuilder offers a commond, simple way to build PushableStreams that allows users to configure backpressure support and whether or not the same data should be fed to multiple Streams.
e.g.
PushableLazyFutureStream<Integer> pushable = new PushableStreamBuilder()
.pushableLazyFutureStream();
pushable.getInput().add(100);
pushable.getInput().add(200);
pushable.getInput().close();
pushable.getStream().forEach(System.out::println)
Will print
100
200
PushableStream<Integer> pushable = new PushableStreamBuilder()
.pushableStream();
pushable.getInput().add(10);
pushable.getInput().add(20);
pushable.getInput().close();
pushable.getStream().forEach(System.out::println)
Will print
10
20
Adding SimpleReact as a Dependency
Gradle
compile group: 'com.aol.simplereact', name:'simple-react', version:'0.83'
Maven
<dependency>
<groupId>com.aol.simplereact</groupId>
<artifactId>simple-react</artifactId>
<version>0.83</version>
<scope>compile</scope>
</dependency>
Javadoc
http://www.javadoc.io/doc/com.aol.simplereact/simple-react/0.83
v0.82 simple-react
New in v0.82
All of the EagerFutureStream methods are asynchronous, but many of them will still wait until all processing of a stage is complete before moving to the next stage. See a list of affecting operators here :-
Alternatives are provided such as limitFutures, skipFutures, sliceFutures, partitionFutures, duplicateFutures, zipFutures, zipFuturesWithIndex etc.
Also new v0.82 is the ability to convert between EagerFutureStream and LazyFutureStream mid-stream and back. So users can switch to LazyFutureStream for the less efficient EagerFutureStream implementations and back again afterwards.
v0.82 also includes some performance / efficiency enhancements such as replace threads with simulated continuations in LazyFutureStream Queue population
Fixes for v0.82
runXXX methods not capturing errors : #19
Adding SimpleReact as a Dependency
Gradle
compile group: 'com.aol.simplereact', name:'simple-react', version:'0.82'
Maven
<dependency>
<groupId>com.aol.simplereact</groupId>
<artifactId>simple-react</artifactId>
<version>0.82</version>
<scope>compile</scope>
</dependency>
Javadoc
http://www.javadoc.io/doc/com.aol.simplereact/simple-react/0.82
v0.81 simple-react
fixes for v0.81
Fix issue with block for LazyFutureStream (was causing it run sequentially)
Fix issue #17 where xxxFutures methods running sequentially.
Fix api issue where some methods returning FutureStream rather than specific type
Adding SimpleReact as a Dependency
Gradle
compile group: 'com.aol.simplereact', name:'simple-react', version:'0.81'
Maven
<dependency>
<groupId>com.aol.simplereact</groupId>
<artifactId>simple-react</artifactId>
<version>0.81</version>
<scope>compile</scope>
</dependency>
Javadoc
http://www.javadoc.io/doc/com.aol.simplereact/simple-react/0.81
v0.80 Simple React : API and stability enhacements
API Enhancements
ReactPools :
Manages a pool of simple-react builder instances (REACTORs).
Streams can be executed within the pool, Pool can block if no capacity available or elastic pools that expand capacity on demand can be used.
ElasticPools
Sequential and Parallel standard REACTOR pools available for ease of use
Operator enhancements
Lot's of new and enhanced operators
zipping operators : combineLatest, withLatest
sharding operators : shard (map, fn)
Control operators - debounce, onePer, xPer, control (fn), skipUntil (stream), takeUntil (stream), jitter, fixedDelay
Batching operators - batchBySize, batchByTime, batch (fn)
Chunking operators - chunkSinceLastRead, chunkSinceLastReadIterator
Future operators for LazyFutureStream - zipFuturesWithIndex,duplicateFutures,zipFutures
clean up of Future operators API
doOnEach - perform an operation after each completion event in this stage, this operation does not form part of a stream / dataflow itself
firstOf - select first FutureStream to emit values
Fixes
Fix for #13
shard
shard allows a Stream to be partitioned by a function into multiple Streams.
skipUntil
takeUntil
Zip operators
combineLatest
combineLatest takes the latest values from two Streams, unlike Zip however it does not wait for both Stream to emit new elements. Will use the last from the other Stream when one Stream emits a new element.
withLatest
withLatest takes the latest value from the current Stream when it emits a new value and combines it with the most recently emitted value from the provided Stream.
Control operators
debounce
http://whatis.techtarget.com/definition/debouncing
Only allow a single element through within a specified time period, elements that aren't passed through are dropped
onePer & xPer
only allow one (or x) elements through in specified time period - slowing down the overall rate of flow. All elements are passed through.
fixedDelay
Imposes a fixedDelay between elements as they pass through the Stream
##Batching & Chunking operators
Batch
Batch takes a function to group elements into batches as they flow through. Provided functions include batchByTime and batchBySize.
chunkSinceLastRead
chunks data passed through since last loop of iteration together into a batch.
Adding SimpleReact as a Dependency
Gradle
compile group: 'com.aol.simplereact', name:'simple-react', version:'0.80'
Maven
<dependency>
<groupId>com.aol.simplereact</groupId>
<artifactId>simple-react</artifactId>
<version>0.80</version>
<scope>compile</scope>
</dependency>
Javadoc
http://www.javadoc.io/doc/com.aol.simplereact/simple-react/0.80
v0.70 of simple-react : auto-closing streams
auto-close queues used in LazyFutureStreams. LazyFutureStream uses queues internally to perform some functions such as flatMap.
Improvements to the reliability of EagerFutureStream and SimpleReactStream when operating sequentially (free threaded mode).
Adding SimpleReact as a Dependency
Gradle
compile group: 'com.aol.simplereact', name:'simple-react', version:'0.70'
Maven
<dependency>
<groupId>com.aol.simplereact</groupId>
<artifactId>simple-react</artifactId>
<version>0.70</version>
<scope>compile</scope>
</dependency>
Javadoc
http://www.javadoc.io/doc/com.aol.simplereact/simple-react/0.70