Project Reactor源码阅读-Scheduler

【响应式编程】Schedulers之线程池共用问题 本篇重点介绍下Reactor中线程池的共用问题。由于在响应式编程中线程数很有限,所以共用时一定要注意,而这个在以前命令式编程中是很少被关注的,需要引起注意。 阅读详情

Reacor在进行线程切换(subscribeOn/publishOn)以及并行计算(runOn)都会使用Scheduler。

通过前面的源码分析,我们知道对于每次切换,实际上都会先基于选择的Scheduler,创建一个对应的Worker,真正异步执行是通过调用Worker#schedule()实现的。

本文主要分析各种Scheduler实现原理。

立即调度-ImmediateScheduler

通过Schedulers.immediate()创建,在调用者线程立即执行任务,底层就是直接调用run()方法执行。

单线程池调度-SingleScheduler

通过Schedulers.single()创建,底层是一个单线程池,将任务交给改单线程池执行。

通过Schedulers.newSingle("test")形式,会为创建名称为test的单线程池。

弹性调度-ElasticScheduler

通过Schedulers.elatic()创建,底层实现比较复杂,我们详细分析一下。

代码示例

@Test
public void testElastic() {
    Scheduler scheduler = Schedulers.elastic();
    for (int i = 0; i < 10; i++) {
        scheduler.schedule(new Task(i, 1000));
    }
    sleep(10000);
}

直接调用scheduler.schedule()提交任务,并发执行。

@Test
public void testElasticWorker() {
    Scheduler.Worker worker = Schedulers.elastic().createWorker();
    for (int i = 0; i < 10; i++) {
        worker.schedule(new Task(i, 1000));
    }
    sleep(10000);
}

调用同一个worker提交任务,异步执行,但是实际上只有1个线程在工作。

Schedulers#elatic()

涉及到到的3个静态常量如下:

static AtomicReference<CachedScheduler> CACHED_ELASTIC = new AtomicReference<>();
static final String ELASTIC  = "elastic"; 
static final Supplier<Scheduler> ELASTIC_SUPPLIER =
      () -> newElastic(ELASTIC, ElasticScheduler.DEFAULT_TTL_SECONDS, true);

Schedulers#cache()

这里的目的是缓存Scheduler,重点是调用supplier.get(),实际执行 newElastic(ELASTIC, ElasticScheduler.DEFAULT_TTL_SECONDS, true);

Schedulers#newElastic()

实际上会调用Factory#newElatic()来创建Scheduler。

Factory#newElastic()

Factory里面创建了ElasticScheduler对象。后续一般都调用createWorker()方法。

我们可以自定义实现Factory接口,实现全局覆盖Schedulers行为。

ElasticScheduler#createWorker()

先调用pick()方法,然后创建ElasticWorker对象。

ElasticScheduler#pick()

  1. 优先从cache中拿数据,如果存在,直接返回缓存对象。
  2. 否则创建CacheService。

cache实际上就是对CacheService进行缓存,因为该对象底层包含线程池,资源消耗高,应该尽可能复用。

在调用dispose()时,会将当前cacheService加入到cache中。

CachedService

重点是调用了ElasticScheduler#get()获取线程池。

ElasticScheduler#get()

每次都创建了一个单线程池!

当我们使用Worker异步执行任务时,实际上是将任务交给对应的单线程池执行。接下来看看为什么直接调用ElasticScheduler#schedule()就能多线程并发执行任务?

ElasticScheduler#schedule()

每次都会重新选择CachedService来执行任务,因此能多线程并发执行任务。

有点类似线程池缓存,只不过一个是针对线程,另一个是针对单线程池。

有边界弹性调度-BoundedElasticScheduler

使用ElaticScheduler有OOM风险:

  1. 可能创建非常多CacheService对象,即可能创建非常多的单线程池。
  2. 可能提交非常多任务。

针对这两个问题,Reactor推荐使用BoundedElasticScheduler,该Scheduler加上了边界限制。

具体来说是增加了线程容量限制和任务队列容量限制,默认为10倍核心线程数和100000, 均可通过配置进行修改。

BoundedElasticScheduler只是在原有ElasticScheduler加上边界限制,底层仍然是单线程池。

并行调度-ParallelScheduler

在启动时,会按照一定数量(默认cpu数量)创建单线程池,创建Worker时会选择一个单线程池。能实现并行调度,是因为会创建多个Worker。

为何底层都是单线程池

不管是弹性调度还是并行调度,Reactor底层都是基于单线程池来实现的。原因在于对于一个流水线上面的操作,理应都是串行处理的。如果使用多个线程的线程池,会存在资源浪费。考虑以下这个例子:

@Test
public void test() {
    delayPublishFlux(10, 1, 100)
            .publishOn(Schedulers.fromExecutorService(Executors.newFixedThreadPool(100)))
            .doOnNext(x -> sleep(1000))
            .subscribe(i -> logInt(i, "消费"));
    sleep(100000);
}

在分析publishOn()源码中,我们知道此时上游的数据是交由Worker异步添加到队列的,此时实际会有多个线程执行。但是下游消费能力有限,根本没必要用多个线程来做。

委派调度-DelegateServiceScheduler

将任务委派给指定的ExecutorService执行。

C++高性能服务器开发实战:从Reactor模型到零拷贝优化 网络编程是构建分布式系统的基石,其核心在于高效管理海量并发连接。传统多线程模型因资源开销巨大而难以应对C10K问题,于是I/O多路复用技术应运而生。通过select、poll到epoll/kqueue的演进,系统能够用单个线程监控大量文件描述符的状态变化,这正是事件驱动架构的原理。这种技术价值在于极大提升了资源利用率,使单机承载数万并发连接成为可能,为高并发服务提供底层支撑。应用场景广泛,从Web服务器、实时通信到游戏后端均依赖于此。本文以热门的“30天C++服务器”项目为蓝本,深入剖析如何基于Reacto 阅读详情

相关推荐

Scrapy生产级爬虫实战:稳定运行、反爬对抗与分布式扩展

Scrapy是基于Twisted异步引擎的Python网络爬虫框架,其核心价值在于构建可长期运行、具备监控能力与弹性扩展性的工业级数据采集系统。它通过调度器优先级队列、Downloader中间件链、Spider状态管理及Pipeline数据契约等机制,实现URL去重、请求重试、动态种子注入与结构化清洗。相比requests+多线程方案,Scrapy在内存控制、异常恢复与反爬适配(如User-Agent加权轮换、代理自动切换、JS渲染协同)上具备显著工程优势。典型应用场景包括电商比价、金融行情抓取、新闻聚合等

CURSED! 514

Reactor Threading and Schedulers线程调度

背景 Reactor是非阻塞响应式编程的一种实现,提供各种异步流操作和编排的API,其本质上是与并发无关的,并不强行使用并发编程,而是提供类库由开发者决定多线程并发模式。 简单实现reactor多线程 根据reactivestream模型可以看出,当调用subscribe时Subscriber和Publisher才建立了发布订阅关系,Subscriber开始请求数据,而在此之前调用链并不会发生数据流动nothinghappensuntilyousubscribe,所以默认情况下,可以简单...

mowushenght的专栏 2830

Scrapy生产级爬虫实战:从环境搭建到京东反爬应对

网络爬虫不仅是HTML解析技术,更是涵盖请求调度、反爬对抗、数据清洗与长期运维的系统工程。Scrapy作为专为生产环境设计的Python爬虫框架,通过内置Scheduler、Middleware和Item Pipeline等机制,将并发控制、User-Agent轮换、Cookie管理、结构化数据管道等80%重复性问题标准化封装。相比requests+BeautifulSoup的手动实现,Scrapy显著提升稳定性、可维护性与扩展性,尤其适用于电商价格监控、竞品数据采集等需应对动态DOM、频繁改版与严格反爬策

angou6476的博客 437

响应式编程:面向数据/事件流的编程范式

响应式编程:面向数据/事件流的编程范式

Infinite Progress 1612

ava异步编程深度解析:CompletableFuture、RxJava与Project Reactor实战指南

(Reactor库),包括它们的特点、用法以及代码示例。RxJava是一个基于Reactive Extensions(Rx)规范的Java库,它提供了一种反应式编程模型,用于处理异步数据流。通过操作符(operators)可以对这些事件流进行变换、过滤、合并、错误处理等操作。它可以用于创建、组合和处理异步任务,支持链式调用、异常处理、回调函数等功能。(代表0-1个事件的异步序列)。Reactor库提供了丰富的操作符、背压支持、与Spring框架深度集成等特点。包中的一个类,它提供了对异步操作的灵活支持。

java专栏 759

Netty源码_02_Netty中的Reactor源码解析

netty最核心的就是reactor线程,对应项目中使用广泛的NioEventLoop,那么NioEventLoop里面到底在干些什么事?netty是如何保证事件循环的高效轮询和任务的及时执行?又是如何来优雅地fix掉jdk的nio bug?带着这些疑问,本篇文章将庖丁解牛,带你逐步了解netty reactor线程的真相[源码基于4.1.6.Final] reactor 线程的启动 NioEventLoop的run方法是reactor线程的主体,在第一次添加任务的时候被启动 NioEventLoop 父

毛毛的专栏 1748

2026 进阶篇:深入理解Spring Reactor响应式编程的核心引擎(源码级解析+实战避坑)

摘要 本文深入解析Spring响应式编程核心引擎Reactor的工作原理,通过源码级分析和实战案例揭示其运行机制。主要内容包括: Reactor核心概念:讲解Publisher-Subscriber模型、Mono与Flux的区别、冷热发布器的特点及其在AI应用中的实际场景。 执行原理:详细剖析懒执行机制、操作符链的数据流动过程,以及背压机制如何实现生产消费平衡。 实战问题:针对AI应用中常见的流式输出卡顿、高并发内存暴涨等问题,从原理层面给出解决方案。 文章特别适合希望深入理解响应式编程本质的Java开发者

架构源启的博客 512

VCS2018在Ubuntu20 18安装步骤

之前在Ubuntu20上下VCS,花了好几天时间,本来想写博客避免以后重复劳动。但由于各种原因拖了一两个月,这次由于疫情原因,期末考试推迟,所以就再次在Ubuntu18上下了VCS,顺便写博客记录。 以下VCS2018安装方法适用于 Ubuntu20、Ubuntu18,亲测可用。其他Linux发行版没试过,但应该步骤差不多。 文章目录安装包安装步骤1、建立安装路径,更改权限2、运行安装器进行安装3、生成License文件4、设置环境变量5、验证License6、启动lmgrd验证软件是否安装成功dvever

s-stone的博客 3万+

快速掌握Redis客户端配置:Redisson实战指南

在分布式系统开发中,Redis作为高性能的内存数据库已成为标配。然而,如何高效配置Redis客户端,确保连接稳定、性能优异,是每个开发者都需要面对的挑战。Redisson作为功能强大的Redis Java客户端,提供了灵活的配置方案,帮助您轻松应对各种复杂场景。本文将带您深入探索Redisson的配置秘籍,从基础到高级,全面掌握配置技巧。🚀 ## 快速上手:5分钟搭建Redisson环境 无

gitblog_00210的博客 468

HFSS之天线设计实例

目录 矩形微带天线 微带天线尺寸计算 微带线的3个关键指标如以下 HFSS设计流程 新建工程并设置求解类型 天线建模 添加求解设置和扫频设置 天线建模步骤 谐振点查看 优化设计 查看天线分析结果 3D增益 Smith圆图 S参数 驻波比 ​ 平面增益 方向性系数\增益\轴比 矩形微带天线 微带天线的概念首先是由Deschamps于1953年提出来的,经过20年左右的发展,Munson和Howell于20世纪70年代初期制造出来了实际的微带天线 一个简单的...

ASH_GUARDIAN的博客 1万+

LwIP在国产MCU的落地实践:从协议栈优化到网络稳定性实战

本文详细介绍了LwIP协议栈在国产GD32F407 MCU上的移植与优化实践,涵盖硬件平台选择、驱动适配、协议栈调优和网络稳定性提升策略。通过内存管理优化、实时操作系统集成和性能测试,为工业物联网应用提供高可靠性网络通信解决方案,显著提升数据传输效率和系统稳定性。

m2n3b4v5c6的博客 270

Java响应式编程–handle用法

JAVA响应式编程reactor中如果需要对一个flux中的数据进行提前返回 可以使用handle 具体如下: @GetMapping("/a") public Mono<Object> a() throws InterruptedException { long begin = System.currentTimeMillis(); Mono<String> m5 = Mono.just("").map(s -> {

weixin_46633487的博客 2615

Ubuntu22.04中通过conda快速部署PyTorch开发环境(CPU/GPU双版本实战)

本文详细介绍了在Ubuntu22.04系统中,如何利用Conda高效部署PyTorch开发环境。文章分别提供了CPU与GPU双版本的实战教程,涵盖环境创建、镜像加速、版本匹配及深度验证等关键步骤,旨在帮助开发者快速搭建稳定、兼容的深度学习环境,从而专注于模型开发。

rose2的博客 558

响应式编程 Webflux

响应式编程

正在努力的小小小白 867

大语言模型推理机制:Prefill、Decode与KV Cache解析

Transformer架构中的推理过程涉及Prefill、Decode和KV Cache三个关键技术阶段。Prefill阶段负责将输入文本转换为token序列并生成初始隐藏状态,其计算复杂度与输入长度成正比。Decode阶段则以自回归方式逐token生成输出,依赖KV Cache存储历史键值对来避免重复计算。KV Cache作为核心优化机制,通过智能管理对话记忆显著提升推理效率。这些技术在聊天机器人、代码生成等场景中至关重要,特别是KV Cache的内存优化策略直接影响大模型在边缘设备等资源受限环境中的部署

weixin_30664615的博客 436

Arduino应用——PWM控制直流电机风扇

Arduino应用——PWM控制直流电机风扇PWM原理实验器件功能描述如何改变文本的样式插入链接与图片实现代码生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入 最近在使用arduino UNO开发板完成课程小作业。其中一个要求设计一个电风扇控制系统,要求能够通过PWM调节风扇的转速。期间搜索了许多例程和方法,但受限于器件,效果不

hypecycle的博客 2万+

Spring Reactor parallel并发与线程切换 实战

第一篇:Spring Reactor 操作符详解 第二篇:Spring Reactor map与flatMap操作符 详解 这一篇讲Reactor 的并发处理,线程切换,背压 parallel 操作符 描述: 并行处理操作符,和我们CPU核数有关,核数越大,并行处理的线程数越多; 需要注意的是,如果我们设置的并行数大于2*核数,其他线程不会被使用; 从下面输出结果能看出,由于我电脑是4核8线程的,并行处理是8,即使我设置了10个线程,也不会进行线程之间切换,所以内容8和9,等上面线程处理完成之后才来处理

以后的今天的博客 4366

UNet改进(19):基于残差注意力模块Residual Attention的高效分割网络设计

本文提出一种结合注意力机制的改进UNet网络,通过引入残差注意力模块(ResidualAttentionBlock)增强医学图像分割性能。该网络在传统UNet的U型结构基础上,创新性地将轻量级注意力机制与残差连接相结合,在编码器-解码器各层级实现特征重标定。改进后的网络具有三方面优势:通过注意力机制自适应聚焦关键特征区域,利用残差连接缓解梯度消失问题,采用模块化设计灵活配置注意力位置。

2501_91516851的博客 781

【Java-webflux】Spring5新特性之webflux反应式编程-Project Reactor

反应式编程(又称为响应式编程),意在解决传统编程方式中响应时间长导致卡顿的问题,通过这种流式的反应式的消息驱动式的编程方式可以让用户有更丝滑的体验,一起感受一下吧!

Ric的博客 1261

【大模型】从0到1:DeepSeek + Coze API调用全攻略,企业,开发个人专属AI智能体使用详解,小白也能轻松上手

本文介绍了如何通过API将Coze智能体集成到自有系统中的完整步骤:1)获取API token和个人工作空间的space_id;2)通过GET请求获取bot_id;3)使用POST发起对话请求,需包含bot_id、user_id和问题内容;4)通过两次API调用异步获取响应消息。文章还解释了Coze采用异步处理机制的原因,并预告了下期将讲解Java调用Coze接口的实现方法。整个过程需要使用API工具进行调试,确保了系统集成的可行性。

qq_27246521的博客 823

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

reactor3 源码分析

文章目录概述本文需要知识点观察者模式lambda表达式reactor源码分析 概述 Reactor 用于创建高效的响应式系统。Reactor 是一个用于JVM的完全非阻塞的响应式编程框架,具备高效的需求管理(即对 “背压(backpressure)”的控制)能力。它与 Java 8 函数式 API 直接集成,比如 CompletableFuture, Stream, 以及 Duration。它提供...

刘本龙的专栏 9291

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

⒈响应式编程 & Project Reactor 概述

响应式编程 Reactive Programming 和 Project Reactive 概述.

O_o 1454

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

Reactor boundedElastic

摘要: boundedElastic调度器专为阻塞操作设计,支持block()等API;而single和parallel仅适用于非阻塞任务,调用阻塞方法会抛出IllegalStateException。自定义调度器可通过实现NonBlocking接口标记为非阻塞专用。关键区别在于:boundedElastic管理弹性线程池处理I/O阻塞,后两者优化低延迟或CPU密集型任务,阻塞操作会破坏其线程模型。开发者需根据任务类型选择调度器,避免混合使用导致异常。(150字)

m0_37607945的博客 639

一文带你彻底了解Java异步

随着RxJava、Reactor等异步框架的流行,异步编程受到了越来越多的关注,尤其是在IO密集型的业务场景中,相比传统的同步开发模式,异步编程的优势越来越明显。那到底什么是异步编程?异...

互扯程序的博客 1068

Project Reactor 核心原理解析

一、开篇 本文将解析 Spring 的 Reactor 项目的源码。主要目的是让自己能深入理解 Reactor 这个项目,以及 Spring 5 和 Spring Boot 2。 Project Reactor 项目地址:https://github.com/reactor Reactor 项目主要包含 Reactor Core 和 Reactor Netty 两部分。Reactor Cor...

johnhuster的专栏 2861

Reactor实例之 muduo 源码分析

首先宣传一下自己的博客, 因为一些不可抗因素同步到csdn, 上面的内容层级分块更清晰一些,内容基本相同Reactor模型中, muduo网络库算是比较简单的一个, 源码也比较容易看, 本文以muduo中的组件为例进行说明, 其他的组件类似。

weixin_41008987的博客 926
上一篇: ReentrantLock 源码
下一篇: parallelStream并行流性能
Java技术那些事儿
博客等级 码龄5年 2306粉丝 2584原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值