java的prefetch()_聊聊FluxFlatMap的concurrency及prefetch参数

本文主要研究下FluxFlatMap的concurrency及prefetch参数

实例

@Test

public void testConcurrencyAndPrefetch(){

int concurrency = 3;

int prefetch = 6;

Flux.range(1,100)

.log()

.flatMap(i -> Flux.just(1,2,3,4,5,6,7,8,9,10).log(),

concurrency,prefetch)

.subscribe();

}

部分输出

23:29:38.515 [main] DEBUG reactor.util.Loggers$LoggerFactory - Using Slf4j logging framework

23:29:38.534 [main] INFO reactor.Flux.Range.1 - | onSubscribe([Synchronous Fuseable] FluxRange.RangeSubscription)

23:29:38.537 [main] INFO reactor.Flux.Range.1 - | request(3)

23:29:38.537 [main] INFO reactor.Flux.Range.1 - | onNext(1)

23:29:38.538 [main] INFO reactor.Flux.Array.2 - | onSubscribe([Synchronous Fuseable] FluxArray.ArraySubscription)

23:29:38.539 [main] INFO reactor.Flux.Array.2 - | request(6)

23:29:38.539 [main] INFO reactor.Flux.Array.2 - | onNext(1)

23:29:38.539 [main] INFO reactor.Flux.Array.2 - | onNext(2)

23:29:38.539 [main] INFO reactor.Flux.Array.2 - | onNext(3)

23:29:38.539 [main] INFO reactor.Flux.Array.2 - | onNext(4)

23:29:38.539 [main] INFO reactor.Flux.Array.2 - | onNext(5)

23:29:38.539 [main] INFO reactor.Flux.Array.2 - | request(5)

23:29:38.539 [main] INFO reactor.Flux.Array.2 - | onNext(6)

23:29:38.539 [main] INFO reactor.Flux.Array.2 - | onNext(7)

23:29:38.539 [main] INFO reactor.Flux.Array.2 - | onNext(8)

23:29:38.539 [main] INFO reactor.Flux.Array.2 - | onNext(9)

23:29:38.539 [main] INFO reactor.Flux.Array.2 - | onNext(10)

23:29:38.539 [main] INFO reactor.Flux.Array.2 - | request(5)

23:29:38.540 [main] INFO reactor.Flux.Array.2 - | onComplete()

23:29:38.540 [main] INFO reactor.Flux.Range.1 - | request(1)

23:29:38.540 [main] INFO reactor.Flux.Range.1 - | onNext(2)

23:29:38.540 [main] INFO reactor.Flux.Array.3 - | onSubscribe([Synchronous Fuseable] FluxArray.ArraySubscription)

23:29:38.540 [main] INFO reactor.Flux.Array.3 - | request(6)

23:29:38.540 [main] INFO reactor.Flux.Array.3 - | onNext(1)

23:29:38.540 [main] INFO reactor.Flux.Array.3 - | onNext(2)

但看外内两个flux的第一次request,可以初步看到分别是concurrency及prefetch

源码解析

Flux

reactor-core-3.1.5.RELEASE-sources.jar!/reactor/core/publisher/Flux.java

/**

* Transform the elements emitted by this {@link Flux} asynchronously into Publishers,

* then flatten these inner publishers into a single {@link Flux} through merging,

* which allow them to interleave.

*

* There are three dimensions to this operator that can be compared with

* {@link #flatMapSequential(Function) flatMapSequential} and {@link #concatMap(Function) concatMap}:

*

*

Generation of inners and subscription: this operator is eagerly

* subscribing to its inners.

*

Ordering of the flattened values: this operator does not necessarily preserve

* original ordering, as inner element are flattened as they arrive.

*

Interleaving: this operator lets values from different inners interleave

* (similar to merging the inner sequences).

*

* The concurrency argument allows to control how many {@link Publisher} can be

* subscribed to and merged in parallel. The prefetch argument allows to give an

* arbitrary prefetch size to the merged {@link Publisher}.

*

*

*

*

* @param mapper the {@link Function} to transform input sequence into N sequences {@link Publisher}

* @param concurrency the maximum number of in-flight inner sequences

* @param prefetch the maximum in-flight elements from each inner {@link Publisher} sequence

* @param the merged output sequence type

*

* @return a merged {@link Flux}

*/

public final Flux flatMap(Function super T, ? extends Publisher extends V>> mapper, int

concurrency, int prefetch) {

return flatMap(mapper, false, concurrency, prefetch);

}

final Flux flatMap(Function super T, ? extends Publisher extends

V>> mapper, boolean delayError, int concurrency, int prefetch) {

return onAssembly(new FluxFlatMap<>(

this,

mapper,

delayError,

concurrency,

Queues.get(concurrency),

prefetch,

Queues.get(prefetch)

));

}

这里使用的是FluxFlatMap

FluxFlatMap

reactor-core-3.1.5.RELEASE-sources.jar!/reactor/core/publisher/FluxFlatMap.java

FluxFlatMap(Flux extends T> source,

Function super T, ? extends Publisher extends R>> mapper,

boolean delayError,

int maxConcurrency,

Supplier extends Queue> mainQueueSupplier,

int prefetch,

Supplier extends Queue> innerQueueSupplier) {

super(source);

if (prefetch <= 0) {

throw new IllegalArgumentException("prefetch > 0 required but it was " + prefetch);

}

if (maxConcurrency <= 0) {

throw new IllegalArgumentException("maxConcurrency > 0 required but it was " + maxConcurrency);

}

this.mapper = Objects.requireNonNull(mapper, "mapper");

this.delayError = delayError;

this.prefetch = prefetch;

this.maxConcurrency = maxConcurrency;

this.mainQueueSupplier =

Objects.requireNonNull(mainQueueSupplier, "mainQueueSupplier");

this.innerQueueSupplier =

Objects.requireNonNull(innerQueueSupplier, "innerQueueSupplier");

}

@Override

public void subscribe(CoreSubscriber super R> actual) {

if (trySubscribeScalarMap(source, actual, mapper, false)) {

return;

}

source.subscribe(new FlatMapMain<>(actual,

mapper,

delayError,

maxConcurrency,

mainQueueSupplier,

prefetch, innerQueueSupplier));

}

这里可以看到subscribe的时候使用了FlatMapMain

FlatMapMain

static final class FlatMapMain extends FlatMapTracker>

implements InnerOperator {

FlatMapMain(CoreSubscriber super R> actual,

Function super T, ? extends Publisher extends R>> mapper,

boolean delayError,

int maxConcurrency,

Supplier extends Queue> mainQueueSupplier,

int prefetch,

Supplier extends Queue> innerQueueSupplier) {

this.actual = actual;

this.mapper = mapper;

this.delayError = delayError;

this.maxConcurrency = maxConcurrency;

this.mainQueueSupplier = mainQueueSupplier;

this.prefetch = prefetch;

this.innerQueueSupplier = innerQueueSupplier;

this.limit = Operators.unboundedOrLimit(maxConcurrency);

}

@Override

public void request(long n) {

if (Operators.validate(n)) {

Operators.addCap(REQUESTED, this, n);

drain();

}

}

@Override

public void onSubscribe(Subscription s) {

if (Operators.validate(this.s, s)) {

this.s = s;

actual.onSubscribe(this);

s.request(Operators.unboundedOrPrefetch(maxConcurrency));

}

}

@SuppressWarnings("unchecked")

@Override

public void onNext(T t) {

if (done) {

Operators.onNextDropped(t, actual.currentContext());

return;

}

Publisher extends R> p;

try {

p = Objects.requireNonNull(mapper.apply(t),

"The mapper returned a null Publisher");

}

catch (Throwable e) {

onError(Operators.onOperatorError(s, e, t, actual.currentContext()));

return;

}

if (p instanceof Callable) {

R v;

try {

v = ((Callable) p).call();

}

catch (Throwable e) {

if (!delayError || !Exceptions.addThrowable(ERROR, this, e)) {

onError(Operators.onOperatorError(s, e, t, actual.currentContext()));

}

return;

}

tryEmitScalar(v);

}

else {

FlatMapInner inner = new FlatMapInner<>(this, prefetch);

if (add(inner)) {

p.subscribe(inner);

}

}

}

//...

}

这个可以理解为对外层flux的操作,可以看到onSubscribe的时候,其内部request的大小为Operators.unboundedOrPrefetch(maxConcurrency),也就是第一个参数concurrency

在onNext操作里头,对里头的flux使用了FlatMapInner

FlatMapInner

static final class FlatMapInner

implements InnerConsumer, Subscription {

FlatMapInner(FlatMapMain, R> parent, int prefetch) {

this.parent = parent;

this.prefetch = prefetch;

//this.limit = prefetch >> 2;

this.limit = Operators.unboundedOrLimit(prefetch);

}

@Override

public void onSubscribe(Subscription s) {

if (Operators.setOnce(S, this, s)) {

if (s instanceof Fuseable.QueueSubscription) {

@SuppressWarnings("unchecked") Fuseable.QueueSubscription f =

(Fuseable.QueueSubscription) s;

int m = f.requestFusion(Fuseable.ANY | Fuseable.THREAD_BARRIER);

if (m == Fuseable.SYNC) {

sourceMode = Fuseable.SYNC;

queue = f;

done = true;

parent.drain();

return;

}

if (m == Fuseable.ASYNC) {

sourceMode = Fuseable.ASYNC;

queue = f;

}

// NONE is just fall-through as the queue will be created on demand

}

s.request(Operators.unboundedOrPrefetch(prefetch));

}

}

@Override

public void request(long n) {

long p = produced + n;

if (p >= limit) {

produced = 0L;

s.request(p);

}

else {

produced = p;

}

}

}

subscribe的时候,request的数量为Operators.unboundedOrPrefetch(prefetch) 这里可以看到这里对prefetch进行右移2操作,相当于除以4,作为limit,limit是个判断,用来对inner的flux的request数量进行限制

小结

flatMap的两个参数concurrency及prefetch,分别是作用于外头及里头的两个flux,第一次request都是使用该值,后续的话,其内部会对request的数量进行判断和调整。

doc

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值