欢迎来到皮皮网官网

【lol跳眼源码】【mybatis源码实例解析】【短信登录java源码】push工具源码_push代码

时间:2024-12-29 01:26:19 来源:数字金融整站源码

1.Vue Router 源码学习笔记4 - pushState和replaceState的工具实现
2.ForkjoinPool -1
3.RocketMQ 5.0: POP 消费模式 原理详解 & 源码解析

push工具源码_push代码

Vue Router 源码学习笔记4 - pushState和replaceState的实现

       在Vue Router中,HTML5History的源码push和replace操作主要通过util/push-state.js中的相应函数来执行,它们依赖window.history.pushState和window.history.replaceState API。代码对于HTML5History,工具如果浏览器支持,源码就按照标准流程进行,代码lol跳眼源码即利用pushState或replaceState改变浏览器的工具历史记录,而不会导致页面刷新。源码

       对于HashHistory,代码浏览器支持与否对操作方式有影响。工具若支持,源码同样采用类似方法,代码通过pushState设置hash部分,工具replaceState则调用window.location.replace替换当前URL。源码然而,代码如果浏览器不支持pushState,会直接操作window.location更改URL,mybatis源码实例解析以#符号为标志。

       MDN文档中提到,pushState需要三个参数:状态对象、标题(通常忽略)和可选的URL。而replaceState与pushState类似,只是替换当前历史项,而非新增,尽管它会在浏览器历史中生成新的短信登录java源码记录。

       当路由更改后,紧接着是视图的同步更新。详细了解这两个方法的使用,可以参考MDN文档:developer.mozilla.org/zh-CN/docs/Web/API/History/pushState。

       继续深入学习,确保在实际项目中正确运用这些原理,实现无缝的路由切换。

ForkjoinPool -1

        ForkJoin是用于并行执行任务的框架, 是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架。Fork就是把一个大任务切分为若干子任务并行的执行,Join就是合并这些子任务的执行结果,最后得到这个大任务的结果。

        下面是一个是一个简单的Join/Fork计算过程,将1—数字相加

        通常这样个模型,你们会想到什么?

        Release Framework ? 常见的处理模型是什么? task pool - worker pool的模型。 但是Forkjoinpool 采取了完全不同的模型。

        ForkJoinPool一种ExecutorService的实现,运行ForkJoinTask任务。ForkJoinPool区别于其它ExecutorService,主要是因为它采用了一种工作窃取(work-stealing)的机制。所有被ForkJoinPool管理的线程尝试窃取提交到池子里的任务来执行,执行中又可产生子任务提交到池子中。

        ForkJoinPool维护了一个WorkQueue的数组(数组长度是2的整数次方,自动增长)。每个workQueue都有任务队列(ForkJoinTask的数组),并且用base、top指向任务队列队尾和队头。work-stealing机制就是工作线程挨个扫描任务队列,如果队列不为空则取队尾的任务并执行。示意图如下

        流程图:

        pool属性

        workQueues是pool的属性,它是WorkQueue类型的数组。externalPush和externalSubmit所创建的workQueue没有owner(即不是worker),且会被放到workQueues的偶数位置;而createWorker创建的workQueue(即worker)有owner,且会被放到workQueues的奇数位置。

        WorkQueue的几个重要成员变量说明如下:

        这是WorkQueue的config,高位跟pool的config值保持一致,而低位则是workQueue在workQueues数组的位置。

        从workQueues属性的介绍中,我们知道,不是所有workQueue都有worker,没有worker的workQueue称为公共队列(shared queue),config的第位就是用来判断是否是公共队列的。在externalSubmit创建工作队列时,有:

        q.config = k | SHARED_QUEUE;

        其中q是新创建的workQueue,k就是q在workQueues数组中的位置,SHARED_QUEUE=1<<,注意这里config没有保留mode的信息。

        而在registerWorker中,则是这样给workQueue的config赋值的:

        w.config = i | mode;

        w是新创建的workQueue,i是其在workQueues数组中的位置,没有设置SHARED_QUEUE标记位

        scanState是workQueue的属性,是int类型的。scanState的低位可以用来定位当前worker处于workQueues数组的哪个位置。每个worker在被创建时会在其构造函数中调用pool的registerWorker,而registerWorker会给scanState赋一个初始值,这个值是奇数,因为worker是由createWorker创建,并会被放到WorkQueues的奇数位置,而createWorker创建worker时会调用registerWorker。

        简言之,worker的scanState初始值是奇数,非worker的scanstate初始值=INACTIVE=1<<,小于0(非worker的workQueue在externalSubmit中创建)。

        当每次调用signalWork(或tryRelease)唤醒worker时,worker的高位就会加1

        另外,scanState<0表示worker未激活,当worker调用runtask执行任务时,scanState会被置为偶数,即设置scanState的最右边一位为0。

        worker休眠时,是这样存储的

        worker的唤醒类似这样:

        在worker休眠的4行伪码中,让ctl的低位的值变为worker.scanState,这样下次就可以通过scanState唤醒该worker。唤醒该worker时,把该worker的preStack设置为ctl低位的值,这样下下次唤醒的worker就是scanState等于该preStack的worker。

        这里通过preStack保存下一个worker,这个worker比当前worker更早地在等待,所以形成一个后进先出的栈。

        runState是int类型的值,控制整个pool的运行状态和生命周期,有下面几个值(可以好几个值同时存在):

        如果runState值为0,表示pool尚未初始化。

        RSLOCK表示锁定pool,当添加worker和pool终止时,就要使用RSLOCK锁定整个pool。如果由于runState被锁定,导致其他操作等待runState解锁(通常用wait进行等待),当runState设置了RSIGNAL,表示runState解锁,并通知(notifyAll)等待的操作。

        剩下4个值都跟runState生命周期有关,都可以顾名思义:

        当需要停止时,设置runState的STOP值,表示准备关闭,这样其他操作看到这个标记位,就不会继续操作,比如tryAddWorker看到STOP就不会再创建worker:

        而tryTerminate对这些生命周期状态的处理则是这样的:

        当前top和base的初始值为 INITIAL_QUEUE_CAPACITY >>>1= (1 << )>>>1 = /2。然后push一个task之后,top+=1,也就是说,top对应的位置是没有task的,最近push进来的task在top-1的位置。而base的位置则能对应到task,base对应最先放进队列的task,top-1对应最后放进队列的task。

        qlock值含义:1: locked,cp怎么修改源码 < 0: terminate; else 0

        即当qlock值位0时,可以正常操作,值=1时,表示锁定

        int SQMASK=0xe,则任何整数跟SQMASK位与后,得到的数就是偶数。

        证明:

        注意这里化为二进制是 ,尤其注意最右边第一位是0,任何数跟最右边第一位是0的数位与后,得到的数就是偶数,因为位与之后,第一位就是0,比如s=A&SQMASK,A可以是任意整数,然后把s按二进制进行多项式展开,则有s=2 n1+2 n2 ……+2^nn,这里n≥1,所以s可以被2整除,即s是偶数。

        所以一个数是奇数还是偶数,看其最右边第一位即可。

        我们知道workQueue有externalPush创建的和createWorker创建的worker,两种方式创建的workQueue,其放置到workQueues的位置是不同的,前者放到workQueue的偶数位置,而后者则放到奇数位置。不同workQueue找到自己在workQueues的位置的算法有点不同。

        下面看一下forkjoin框架获取workQueues中的偶数位置的workQueue的算法:

        这样就能获取workQueues的偶数位置的workQueue。m保证m & r & SQMASK这整个运算结果不会超出workQueues的下标,SQMASK保证取到的是偶数位置的workQueue。这里有一个有趣的现象,假设0到workQueues.length-1之间有n个偶数,m & r & SQMASK每次都能取到其中一个偶数,而且连续n次取到的偶数不会出现重复值,散列性非常好。而且是循环的,即1到n次取n个不同偶数,n+1到2n也是取n次不同偶数,此时n个偶数每个都被重新取一次。下面分析下r值有什么秘密,为何能保证这样的散列性

        ThreadLocalRandom内有一常量PROBE_INCREMENT = 0x9eb9,以及一个静态的probeGenerator =new AtomicInteger() ,然后每个线程的probe= probeGenerator.addAndGet(PROBE_INCREMENT)所以第一个线程的probe值是0x9eb9,第二个线程的值就是0x9eb9+0x9eb9,第三个线程的值就是0x9eb9+0x9eb9+0x9eb9以此类推,整个值是线性的,可以用y=kx表示,其中k=0x9eb9,x表示第几个线程。这样每个线程的probe可以保证不一样,而且具有很好的离散性。

        实际上,可以不用0x9eb9这个值,用任意一个奇数都是可以的,比如1。如果用1的话,probe+=1,这样每个线程的probe就都是不同的,而且具有很好的离散性。也就是说,假设有限制条件probe<n,超过n则产生溢出。则probe自加n次后才会开始出现重复值,n次前probe每次自加的值都不同。实际上用任意一个奇数,都可以保证probe自加n次后才会开始出现重复值,有兴趣可看本文最后附录部分。由于奇数的离散性,所以只要线程数小于m或者SQMASK两者中的最小值,则每个线程都能唯一地占据一个ws中的一个位置

        当一个操作是在非ForkjoinThread的线程中进行的,则称该操作为外部操作。比如我们前面执行pool.invoke,invoke内又执行externalPush。由于invoke是在非ForkjoinThread线程中进行的(这里是在main线程中进行),所以是一个外部操作,调用的是externalPush。之后task的执行是通过ForkJoinThread来执行的,所以task中的fork就是内部操作,调用的是push,把任务提交到工作队列。其实fork的实现是类似下面这样的:

        即fork会根据执行自身的线程是否是ForkJoinThread的实例来判断是处于外部还是内部。那为何要区分内外部?

        任何线程都可以使用ForkJoin框架,但是对于非ForkJoinThread的线程,它到底是怎样的,ForkJoin无法控制,也无法对其优化。因此区分出内外部,这样方便ForkJoin框架对任务的执行进行控制和优化

        forkJoinPool.invoke(task)是把任务放入工作队列,并等待任务执行。源码如下

        这里externalPush负责任务提交,externalPush源码如下:

RocketMQ 5.0: POP 消费模式 原理详解 & 源码解析

       RocketMQ 5.0 引入 Pop 消费模式,用于解决 Push 消费模式存在的痛点。Pop 消费模式将客户端的重平衡逻辑迁移至 Broker 端,使得消息消费过程更加高效,避免消息堆积和横向扩展能力受限的问题。引入轻量化客户端后,通过 gRPC 封装 Pop 消费接口,实现了多语言支持,无需在客户端实现重平衡逻辑。活动页面网页源码

       Pop 消费模式的原理在于客户端仅需发送 Pop 请求,由 Broker 端根据请求分配消息队列并返回消息。这样可以实现多客户端同时消费同一队列,避免单一客户端挂起导致消息堆积,同时也消除了频繁重平衡导致的消息积压问题。

       Pop 消费流程涉及消息拉取、不可见时间管理、消费失败处理和消息重试等关键环节。消息拉取时,系统会为一批消息生成 CheckPoint,并在 Broker 内存中保存,以便与 ACK 消息匹配。消息不可见时间机制确保在规定时间内未被 ACK 的消息将被重试。消费失败时,客户端通过修改消息不可见时间来调整重试策略。当消费用时超过预设时间,Broker 也会将消息放入重试队列。通过定时消息,Broker 可以提前消费重试队列中的消息,与 ACK 消息匹配,实现高效消息处理。

       在 Broker 端,重平衡逻辑也进行了优化。Pop 模式的重平衡允许多个消费者同时消费同一队列,通过 popShareQueueNum 参数配置额外的负载获取队列次数。Pop 消息处理涉及从队列中 POP 消息、生成 CheckPoint 用于匹配 ACK 消息、以及存储 CheckPoint 与 Ack 消息匹配。Broker 端还通过 PopBufferMergeService 线程实现内存与磁盘中的 CheckPoint 和 Ack 消息匹配,以及消息重试处理。

       源码解析部分涉及 Broker 端的重平衡逻辑、Pop 消息处理、Ack 消息处理、CheckPoint 与 Ack 消息匹配逻辑等关键组件的实现细节,这些细节展示了 RocketMQ 5.0 如何通过优化消费模式和流程设计,提升消息消费的效率和稳定性。

copyright © 2016 powered by 皮皮网   sitemap