Spring Reactive Development- flatMap, flatMapSequential and concatMap

Ractive 开发过程中如果遇到和Operator内操作元素返回一个 Mono或者Flux时我们知道都要使用flatMap进行抻平操作

其中有flatMap, flatMapSequential and concatMap 比较容易混淆 下面写几个例子进行下区分:

mock Reactive数据查询服务:

//mock reactive data search service    
private Mono<String> getEmployeeName(String id) {
        Map<String, String> employees = new HashMap<>();
        employees.put("1", "aSha");
        employees.put("2", "billy");
        employees.put("3", "cindy");
        employees.put("4", "davide");
        employees.put("5", "ella");
        employees.put("6", "flee");
        employees.put("7", "galosh");
        employees.put("8", "hank");

        String name = employees.get(id);
        try {
//            Thread.sleep(new Random().nextInt(100)*100);
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException("Thread sleep Error!!!");
        }
        if (StringUtils.isBlank(name)) {
            throw new RuntimeException("Not Found!!!");
        }
        return Mono.just(name);
    }

  

1. flatMap

    @Test
    public void testFlatMap() {
        List<String> employeeIds = Arrays.asList("1", "2", "3", "4", "5", "6", "7", "8");
        Flux<String> nameFlux = Flux.fromIterable(employeeIds)
                                    .flatMap(this::getEmployeeName)
                                    .log();
        StepVerifier.create(nameFlux)
                    .expectNextCount(8)
                    .verifyComplete();
    }

// ==========================================
// 22:12:53.173 [main] INFO reactor.Flux.FlatMap.1 - onNext(aSha)
// 22:12:54.178 [main] INFO reactor.Flux.FlatMap.1 - onNext(billy)
// 22:12:55.179 [main] INFO reactor.Flux.FlatMap.1 - onNext(cindy)
// 22:12:56.180 [main] INFO reactor.Flux.FlatMap.1 - onNext(davide)
// 22:12:57.185 [main] INFO reactor.Flux.FlatMap.1 - onNext(ella)
// 22:12:58.187 [main] INFO reactor.Flux.FlatMap.1 - onNext(flee)
// 22:12:59.189 [main] INFO reactor.Flux.FlatMap.1 - onNext(galosh)
// 22:13:00.190 [main] INFO reactor.Flux.FlatMap.1 - onNext(hank)
// 22:13:00.192 [main] INFO reactor.Flux.FlatMap.1 - onComplete()

 但是flatMap不确保顺序的, 当内部处理复杂的时候可能会导致顺序混乱

例如为了提高效率使用parallelScheduler:

@Test
    public void testFlatMapParallelScheduler() {
        List<String> employeeIds = Arrays.asList("1", "2", "3", "4", "5", "6", "7", "8");
        Flux<String> nameFlux = Flux.fromIterable(employeeIds)
                                    .window(2)
                                    .flatMap(identities -> identities.flatMap(this::getEmployeeName).subscribeOn(parallel()))
                                    .log();
        StepVerifier.create(nameFlux)
                    .expectNextCount(8)
                    .verifyComplete();
    }
// ================================
// 22:12:16.987 [main] INFO reactor.Flux.FlatMap.1 - onNext(aSha)
// 22:12:17.988 [main] INFO reactor.Flux.FlatMap.1 - onNext(billy)
// 22:12:18.990 [parallel-3] INFO reactor.Flux.FlatMap.1 - onNext(ella)
// 22:12:18.990 [parallel-3] INFO reactor.Flux.FlatMap.1 - onNext(cindy)
// 22:12:18.990 [parallel-3] INFO reactor.Flux.FlatMap.1 - onNext(galosh)
// 22:12:19.991 [parallel-2] INFO reactor.Flux.FlatMap.1 - onNext(davide)
// 22:12:19.991 [parallel-2] INFO reactor.Flux.FlatMap.1 - onNext(flee)
// 22:12:19.991 [parallel-2] INFO reactor.Flux.FlatMap.1 - onNext(hank)
// 22:12:19.991 [parallel-2] INFO reactor.Flux.FlatMap.1 - onComplete()

2 concatMap

concatMap 他是深度优先,可以深度保持数据的处理顺序,但是效率就没有提高。

	@Test
	public void testConcatMapParallelScheduler() {
		List<String> employeeIds = Arrays.asList("1", "2", "3", "4", "5", "6", "7", "8");
		Flux<String> nameFlux = Flux.fromIterable(employeeIds)
									.window(2)
									.concatMap(identities -> identities.flatMap(this::getEmployeeName).subscribeOn(parallel()))
									.log();
		StepVerifier.create(nameFlux)
					.expectNextCount(8)
					.verifyComplete();
	}
// =================================
// 22:15:41.513 [parallel-1] INFO reactor.Flux.ConcatMap.1 - onNext(aSha)
// 22:15:42.516 [parallel-1] INFO reactor.Flux.ConcatMap.1 - onNext(billy)
// 22:15:43.521 [parallel-2] INFO reactor.Flux.ConcatMap.1 - onNext(cindy)
// 22:15:44.525 [parallel-2] INFO reactor.Flux.ConcatMap.1 - onNext(davide)
// 22:15:45.528 [parallel-3] INFO reactor.Flux.ConcatMap.1 - onNext(ella)
// 22:15:46.530 [parallel-3] INFO reactor.Flux.ConcatMap.1 - onNext(flee)
// 22:15:47.532 [parallel-4] INFO reactor.Flux.ConcatMap.1 - onNext(galosh)
// 22:15:48.533 [parallel-4] INFO reactor.Flux.ConcatMap.1 - onNext(hank)
// 22:15:48.534 [parallel-4] INFO reactor.Flux.ConcatMap.1 - onComplete()

3 flatMapSequential

flatMapSequential 是介于flatMap 与concatMap之间的,既能够保证顺序,又可以提高效率, 不过这个顺序保证是最终结果顺序一致

	@Test
	public void testFlatMapSequentialParallelScheduler() {
		List<String> employeeIds = Arrays.asList("1", "2", "3", "4", "5", "6", "7", "8");
		Flux<String> nameFlux = Flux.fromIterable(employeeIds)
									.window(2)
									.flatMapSequential(identities -> identities.flatMap(this::getEmployeeName).subscribeOn(parallel()))
									.log();
		StepVerifier.create(nameFlux)
					.expectNextCount(8)
					.verifyComplete();
	}
// ==========================================
// 22:18:45.966 [parallel-1] INFO reactor.Flux.MergeSequential.1 - onNext(aSha)
// 22:18:46.967 [parallel-1] INFO reactor.Flux.MergeSequential.1 - onNext(billy)
// 22:18:46.968 [parallel-1] INFO reactor.Flux.MergeSequential.1 - onNext(cindy)
// 22:18:46.968 [parallel-1] INFO reactor.Flux.MergeSequential.1 - onNext(davide)
// 22:18:46.968 [parallel-1] INFO reactor.Flux.MergeSequential.1 - onNext(ella)
// 22:18:46.968 [parallel-1] INFO reactor.Flux.MergeSequential.1 - onNext(flee)
// 22:18:46.968 [parallel-1] INFO reactor.Flux.MergeSequential.1 - onNext(galosh)
// 22:18:46.968 [parallel-1] INFO reactor.Flux.MergeSequential.1 - onNext(hank)
// 22:18:46.968 [parallel-1] INFO reactor.Flux.MergeSequential.1 - onComplete()

  

参考:

https://www.youtube.com/watch?v=p7upvc5xcOs  

posted on 2020-12-29 22:20  涤生-三省吾身  阅读(600)  评论(0编辑  收藏  举报

导航