1.死磕 Hutool 源码系列(一)——StrUtil 源码解析
2.Vue3源码系列 (一) watch
3.[转]Megatron-LM源码系列(八): Context Parallel并行
4.搞懂React源码系列-React Diff原理
5.Vue3源码系列(七):createApp— 一切的系列起源
6.UE4 LevelSequence源码剖析(一)
死磕 Hutool 源码系列(一)——StrUtil 源码解析
深入解析StrUtil源码 在实际项目中,String数据结构的源码源码使用极为频繁,因此对字符串的大全操作代码也相对繁多,这些操作往往独立于具体业务之外,系列为实现代码简洁性和可读性,源码源码我们通常将对String的大全jabberd 源码分析各种操作封装成静态工具类,这就是系列本文主角——StrUtil。StrUtil几乎囊括了我们能想到的源码源码所有字符串通用操作方法。 源码探索 StrUtil作为静态工具类,大全内部仅包含静态方法和静态常量。系列其设计者贴心地预设了诸多开发中常用的源码源码字符,如空字符、大全空格、系列制表符等,源码源码避免了硬编码,大全便于直接调用。 方法归类 通过方法脑图,我们对StrUtil的方法有了大致了解。每个方法名简洁明了,见名知意。 分类包括:判空类方法
去前后空格类方法
查找类方法
源码包含众多静态方法,本文首篇总结了部分方法,后续会继续更新。Vue3源码系列 (一) watch
本文深入解析 Vue3 中 watch 的机制。首先,我们了解 watch 接收三个参数:监听的数据源 source、回调 cb 以及可选的 options。options 包括 immediate、deep、flush、onTrack 和 onTrigger,用于控制立即执行、深度监听、回调时机以及收集依赖和触发更新时的自定义函数。回调 cb 接收 value、oldValue 和 onCleanUp 参数,用于执行特定操作,bskd指标源码如响应表格页码变化重新请求数据,并在副作用清理时调用 onCleanUp 函数。
watch 支持监听单个数据或多个数据,其参数类型包括 WatchSource、响应式对象、MultiWatchSources 和 Readonly。单个数据源可以是 WatchSource 或响应式的对象,多个数据源则为 MultiWatchSources 或 Readonly。
watch 的核心在于 doWatch 函数,它接收与 watch 类似的参数。在源码中,doWatch 负责实现 watch 的逻辑。首先,它会检查是否提供了回调函数 cb。如果没有,且 options 中设置了 immediate 和 deep,会抛出警告,因为这些选项只对有回调的 doWatch 签名有效。接着,设置 getter,并配置强制触发和深度监听。根据 source 的类型,doWatch 进行不同的处理。
在处理源数据后,doWatch 会创建 effect,这是 Vue3 中实现响应式的关键。effect 通过 getter 获取当前值,然后在回调函数中使用 newValue 和 oldValue。这使得 watch 能在数据变化时触发回调函数,执行相应的操作。
总结,本文详细阐述了 Vue3 中 watch 的工作原理,从参数类型、回调函数到核心实现 doWatch 函数,全面深入地解析了 watch 的机制,帮助开发者更好地理解和运用 Vue3 的ca辅助源码响应式特性。通过本文,读者可以深入了解 Vue3 watch 的内部工作流程,为构建高效、响应式的 Vue 应用提供技术支持。
[转]Megatron-LM源码系列(八): Context Parallel并行
原文链接: Megatron-LM源码系列(八): Context Parallel并行
Context Parallel并行(CP)与sequence并行(SP)相比,核心差异在于SP只针对Layernorm和Dropout输出的activation在sequence维度进行切分,而CP则进一步扩展,对所有input输入和所有输出activation在sequence维度上进行切分,形成更高效的并行处理策略。除了Attention模块外,其他如Layernorm、Dropout等模块在CP并行中无需任何修改,因为它们在处理过程中没有涉及多token间的交互。
Attention模块之所以特殊,是因为在计算过程中,每个token的查询(query)需要与同一sequence中其他token的键(key)和值(value)进行交互计算,存在内在依赖性。因此,在进行CP并行时,计算开始前需要通过allgather通信手段获取所有token的KV向量,反向计算时则通过reduce_scatter分发gradient梯度。
为了降低显存使用,前向计算阶段每个GPU仅保存部分KV块,反向阶段则通过allgather通信获取全部KV数据。这些通信操作在特定的rank位置(相同TP组内)进行,底层通过send和recv等操作实现allgather和reduce_scatter。
以TP2-CP2的transformer网络为例,CP并行的通信操作在Attention之前执行,其他则为TP通信。AG表示allgather,RS表示reduce_scatter,AG/RS表示前向allgather反向reduce_scatter,RS/AG表示前向reduce_scatter反向allgather。
TP2对应为[GPU0, GPU1], [GPU2, GPU3],CP2指的就是TP组相同位置的rank号,即[GPU0,源码定制价格 GPU2], [GPU1, GPU3]。CP并行类似于Ring Attention,但提供了OSS与FlashAttention版本,并去除了冗余的low-triangle causal masking计算。
LLM常因序列长度过长而导致显存耗尽(OOM)。传统解决方法包括重计算或扩大TP(tensor parallel)大小,但各自存在计算代价增加或线性fc计算时间减少与通信难以掩盖的问题。CP则能更高效地解决这一问题,每个GPU处理一部分序列,同时减少CP倍的通信和计算量,同时保持TP不变,使得activation量也减少CP倍。性能优化结果展示于图表中,用户可通过指定--context-parallel-size在Megatron中实现CP。
具体源码实现以Megatron-Core 0.5.0版本为例进行说明。
参考资料:
搞懂React源码系列-React Diff原理
时隔2年,重新审视React源码,理解了许多过去未曾明晰的内容。本文聚焦于通过实际案例结合相关React源码,集中探讨React Diff原理。我们将使用当前最新React版本:..1。同时,今年计划推出“搞懂React源码系列”,旨在以通俗易懂的方式深入解析React的核心部分。年,该系列将涵盖以下内容:
React Diff原理
React 调度原理
搭建阅读React源码环境-支持所有版本断点调试
React Hooks原理
欢迎关注我的博客。
在深入Diff算法之前,有必要先理解React Fiber。虽然Fiber并不复杂,但全面理解需要时间。本文重点是Diff原理,因此Fiber介绍将简要进行。
Fiber是React中的抽象节点对象,它将所有节点连接成链表树。每个Fiber可能包含子Fiber、相邻Fiber以及父Fiber。React使用链表形式连接所有Fiber,源码街租车形成树结构。Fiber还带有副作用标签(effectTag),如替换(Placement)和删除(Deletion),用于后续更新DOM。
值得注意的是,React Diff过程中,除了Fiber,还涉及基本的React元素对象,如将foo编译后的对象为:{ type: 'div', props: { children: 'foo' } }。
Diff过程始于reconcileChildren(...)
总流程如下:
reconcileChildren(...)
在Diff时,比较中的旧内容为Fiber,而新内容为React元素、文本或数组。新内容为对象时,流程分为两步:reconcileSingleElement(...)和placeSingleChild(...)。以React元素为例,流程如下:
reconcileSingleElement(...)
这里正式开始Diff,child为旧内容Fiber,element为新内容,它们的元素类型不同。React将“删除”旧内容Fiber及其所有相邻Fiber(添加Deletion标签),并基于新内容生成新的Fiber。然后将新Fiber设置为父Fiber的child。
如果新旧内容的元素类型相同,则通过fiber复用生成新的Fiber。同样设置为父Fiber的child。
总结新内容为React元素的Diff流程:
reconcileChildren(...)
新内容为文本时,逻辑与新内容为React元素类似。新内容为数组时,通过遍历数组元素,与React元素的处理方式类似,生成新的Fiber。
总结新内容为数组的Diff流程:
reconcileChildrenArray(...)
Diff的三种情况总结:比较结果相同:复用旧内容Fiber,结合新内容生成新Fiber
比较结果不同:仅通过新内容创建新Fiber
然后给旧内容Fiber添加替换标签,或给旧内容Fiber及其所有相邻元素添加删除标签。最后将新的(第一个)Fiber设为父Fiber的child。Vue3源码系列(七):createApp— 一切的起源
在使用Vue3构建前端项目时,我们经常在main.js/main.ts中通过createApp这个API创建应用程序实例。这篇文章将深入探讨createApp背后的故事。首先,让我们了解几个关键的类型:App: createApp返回的实例,包含了项目常用方法,链式调用友好,兼容Vue2的filter,并提供了内部属性。
AppConfig: 应用配置,包含Vue2中常见的选项,如组件合并策略、全局属性和编译器设置等。
AppContext: 上下文对象,记录组件、指令等信息,支持热更新和Vue2 filter的兼容。
Plugin: 与Vue2类似,Plugin和install方法定义清晰,可以是函数或对象。
CreateAppFunction: createApp函数的类型,接受根组件和可选的根组件属性。
实际上,Vue3的起点在于createApp API,它定义在packages/runtime-dom/src/index.ts。我们从这里开始追踪其内部流程:createApp: 乍看之下,createApp似乎在renderer上,它由createRenderer创建。createRenderer在packages/runtime-core/src/renderer.ts中定义,调用baseCreateRenderer,这个函数包含diff操作方法,但核心的createApp源自createAppAPI。
createAppAPI: 在baseCreateRenderer的返回值中,createAppAPI接收render和hydrate方法,将它们组合成我们熟知的createApp。这个函数约行,逻辑清晰地构造了应用实例。
虽然我们已经了解了createApp的基本创建过程,但render函数的详细过程尚未揭示。后续会进一步剖析render的执行机制。UE4 LevelSequence源码剖析(一)
UE4的LevelSequence源码解析系列将分四部分探讨,本篇聚焦Runtime部分。Runtime代码主要位于UnrealEngine\Engine\Source\Runtime\MovieScene目录,结构上主要包括Channels、Evaluation、Sections和Tracks等核心模块。
ALevelSequenceActor是Runtime的核心,负责逐帧更新,它包含UMovieSceneSequence和ULevelSequencePlayer。ALevelSequenceActor独立于GameThread更新,并且在Actor和ActorComponent更新之前,确保其在RuntTickGroup之前执行。
IMovieScenePlaybackClient的关键接口用于绑定,编辑器通过IMovieSceneBindingOwnerInterface提供直观的蓝图绑定机制。UMovieSceneSequence是LevelSequence资源实例,它支持SpawnableObject和PossessableObject,便于控制对象的拥有和分离。
ULevelSequencePlayer作为播放控制器,由ALevelSequenceActor的Tick更新,具有指定对象在World和Sublevel中的功能,还包含用于时间控制的FMovieSceneTimeController。UMovieSceneTrack作为底层架构,由UMovieSceneSections组成,每个Section封装了Section的帧范围和对应Channel的数据。
序列的Eval过程涉及EvalTemplate和ExecutionTokens,它们协同工作模拟Track。FMovieSceneEvaluationTemplate定义了Track的模拟行为,而ExecutionTokens则是模拟过程中的最小单元。真正的模拟操作在FMovieSceneExecutionTokens的Apply函数中执行,通过BlendingAccumulator进行结果融合。
自定义UMovieSceneTrack需要定义自己的EvaluationTemplate,这部分将在编辑器拓展部分详细讲解。序列的Runtime部分展示了如何在GameThread中高效管理和模拟场景变化,为后续的解析奠定了基础。
Vue3源码系列 (四) ref
一般而言,reactive用于定义响应式对象,而ref则用于定义响应式原始值。前文已介绍reactive,了解到通过Proxy对目标对象进行代理实现响应式,非对象原始值的响应式问题则由ref解决。
ref和shallowRef各有三种重载,参数不同,都返回Ref/ShallowRef类型的值。createRef函数用于创建响应式值,类似reactive,createRef也是通过createReactiveObject创建响应式对象。而createRef返回RefImpl实例。
RefImpl是ref的核心内容,构造函数接收两个参数,value是传入的原始值,__v_isShallow用于区分深层/浅层响应式,isShallow()函数利用这个属性做判断。在Ref中,_value属性存储实际值,dep属性存储依赖,在class的getter中通过trackRefValue(this)收集依赖,在setter中调用triggerRefValue(this, newVal)。
trackRefValue用于收集Ref依赖,接收RefBase类型值,在ref函数中接收RefImpl实例。shouldTrack用于暂停和恢复捕获依赖的标志,activeEffect标记当前活跃的effect。内部调用trackEffects函数收集依赖,该函数来自effect模块。
triggerRefValue函数用于触发Ref的响应式更新,triggerEffects函数来自effect模块。
Vue3还提供了自定义的Ref,可以传入getter和setter,自由选择track和trigger时机。
在setup函数中返回参数时,使用toRef创建ObjectRefImpl实例对响应式对象的某个属性进行解构。
ObjectRefImpl通过_object属性引用原始响应式对象,在getter中通过_object访问值,依赖收集由_object完成;在setter中,通过引用_object达到赋值操作,从而在_object中触发更新。toRef判断入参是否是Ref,是则直接返回,否则返回ObjectRefImpl。toRefs对传入的对象/数组进行遍历并执行toRef解构。
golang源码系列---手把手带你看heap实现
heap包定义实现堆所需结构与操作方法,包含Interface接口,允许实现堆功能。Push和Pop方法分别用于添加元素与移除堆顶元素。
构建堆时需实现sort.Interface接口。Heap包内部仅包含两个非导出函数,作为堆导出方法的基础。
down函数将堆顶元素下沉,保持堆结构。up函数则将当前节点上浮,确保堆的性质。
Init函数初始化堆结构。Push与Pop方法用于添加与移除元素,底层依赖up和down函数。
Remove方法移除指定位置元素,类似Pop,通过上浮下沉操作恢复堆结构。
Fix函数在节点值变化后,用于修复堆结构。
使用案例:以学生信息为例,根据年龄排序,并按升序输出。
总结:heap包提供实现堆所需的接口与方法,通过非导出函数与导出方法的配合,完成堆的操作与构建。实例化堆后,可根据具体需求使用Push、Pop、Remove与Fix方法,实现元素的添加、删除与结构修复。
[转]Megatron-LM源码系列(六):Distributed-Optimizer分布式优化器实现Part1
Megatron-LM源码系列(六): Distributed-Optimizer分布式优化器实现Part1
使用说明
在Megatron中,通过使用命令行参数`--use-distributed-optimizer`即可开启分布式优化器,这一功能在`megatron/arguments.py`文件中设置。分布式优化器的核心思想是将训练过程中优化器的状态均匀分布到不同数据并行的rank结点上,实现相当于使用Zero-1训练的效果。
当使用`--use-distributed-optimizer`参数时,系统将检查两个条件:`args.DDP_impl == 'local'`(默认开启)和`args.use_contiguous_buffers_in_local_ddp`(默认开启)。这些条件确保了优化器的正确配置与运行环境的兼容性。
分布式优化器节省的理论显存值依赖于参数类型和梯度类型。具体来说,根据参数和梯度的类型,每个参数在分布式环境中将占用特定数量的字节。例如,假设`d`代表数据并行的大小(即一个数据并行的卡数),则理论字节数量可通过以下公式计算得出。
实现介绍
这部分内容将深入探讨分布式优化器的实施细节。
3.1 程序入口
通过分析初始化过程和系统调用,我们可以深入理解分布式优化器的启动机制。
3.2 grad buffer初始化(DistributedDataParallel类)
在这个部分,我们关注DistributedDataParallel类及其在初始化grad buffer时的功能与作用,这是实现分布式训练中关键的一环。
3.3 分布式优化器实现(DistributedOptimizer类)
通过实现DistributedOptimizer类,Megatron-LM允许模型在分布式环境中进行有效的训练。这包括对优化器状态的管理、梯度聚合与分散等关键操作。
后续将会继续探讨关于分布式优化器实现的更多内容,读者可参考Megatron-LM源码系列(七):Distributed-Optimizer分布式优化器实现Part2以获得深入理解。
参考文献