In short, is there any solution to resolve backpressure in RxJava without resorting to dropping items, serializing operations or unbounded buffering?
Consider the following task as an example of when this could be useful.
- Reading data from disk into memory
- Compressing the data
- Transmitting the compressed data over the network
The straightforward approach is to do all tasks sequentially on a single background thread, as in:
observeBlocksOfFileContents(file).
.subscribeOn(backgroundScheduler)
.map(compressBlock)
.subscribe(transmitBlock);
While this works without issue, from a performance perspective it is suboptimal as the runtime is the sum of all three operations as opposed to the maximum of them as it is when run in parallel:
observeBlocksOfFileContents(file).
.subscribeOn(diskScheduler)
.observeOn(cpuScheduler)
.map(compressBlock)
.observeOn(networkScheduler)
.subscribe(transmitBlock);
This can however fail due to backpressure if the data is read from disk faster than it can be compressed and transmitted. The usual backpressure solutions are undesirable for the following reasons:
- Drop items: the file must be transmitted in full without missing pieces
- Serialize on single thread: the performance improvement of pipelining is lost
- Callstack blocking: not supported in RxJava
- Increase observeOn buffers: memory consumption may become several times the file size
- Reimplement observeOn without MissingBackpressureException: a lot of work and breaks fluent API
Are there any other solutions? Or is this something that fundamentally does not fit the ReactiveX observable model?