UniRx 入门
Reactive X 是 Reactive Extensions 的缩写,一般简写为 Rx,最初是 LINQ 的一个扩展,由微软的团队开发,Rx 是一个编程模型,目标是提供一致的编程接口,帮助开发者更方便的处理异步数据流,支持大部分流行语言。
Rx是一个函数库,让开发者可以利用可观察序列和 LINQ 风格查询操作符来编写异步和基于事件的程序,使用Rx,开发者可以用Observables 表示异步数据流,用 LINO 操作符查询异步数据流,用 Schedulers 参数化异步数据流的并发处理,Rx可以这样定义︰
Rx = Observables + LINQ + Schedulers
Rx 结合了观察者模式、迭代器模式和函数式编程的精华。UniRx 就是 Unity Reactive Extensions,是为 Unity 平台设计的响应式编程框架。
在游戏中,⼤部分的逻辑都是在时间上异步的。⽐如动画的播放、声⾳的播放、⽹络请求、资源加载/卸载、场景过渡等。
在实现 异步逻辑时经常⽤到⼤量的回调,最终随着项⽬的扩张导致传说中的”回调地狱”。
相对较好地⽅法则是使⽤消息/事件的发送,结果导致“消息满天⻜”,导致代码⾮常难以阅读。
⽽ UniRx 的出现刚好解决了这个问题,它介于回调和事件之间。
常用API
监听 mono 生命周期函数
Observable.EveryUpdate() // 开启 Update 的事件监听.Subscribe(_ => // 订阅/处理事件{Debug.Log("Update");});Observable.EveryLateUpdate().Subscribe(_ =>{Debug.Log("LateUpdate");});Observable.EveryFixedUpdate().Subscribe(_ =>{Debug.Log("FixedUpdate");});Observable.EveryEndOfFrame().Subscribe(_ =>{Debug.Log("EndOfFrame");});Observable.EveryApplicationFocus().Subscribe(focuse =>{Debug.Log("Focus: " + focuse);});
如果在 Update ⽅法中,除了实现⿏标事件监听这个功能之外,还要实现其他的功能。那么 Update ⾥就会充斥着⼤量的状态判断等逻辑。代码⾮常不容易阅读。
⽽ UniRx 提供了⼀种编程思维,使得平时⼀些⽐较难实现的异步逻辑,使⽤ UniRx 轻松搞定,并且不失代码的可读性
参数下划线 _ 表示帧数,这里用不到就用 _ 表示
定时功能
Observable.Timer(TimeSpan.FromSeconds(5.0f)).Subscribe(_ =>{Debug.Log("do something");});
AddTo 与 Trigger
Observable.Timer(TimeSpan.FromSeconds(2.0f)).Subscribe(_ =>{Debug.Log("延时两秒"); }).AddTo(this);this.OnDestroyAsObservable().Subscribe(_ =>{Debug.Log("OnDestroy");});this.OnCollisionEnterAsObservable().Subscribe(collision =>{Debug.Log("CollisionEnter");});
AddTo 会在 GameObject 上添加一个 ObservableDestroyTrigger 脚本监听它的 OnDestroy 事件,当 GameObject 销毁时也会销毁正在运行的 UniRx 任务,即 GameObject 销毁时,这个 Timer 也会销毁,避免空引用异常。
ObservableDestroyTrigger 是一个 Trigger,Trigger 大部分都是都是 XXXAsObsrevable 命名形式的。
在使用 Trigger 的 GameObject 上都会挂上对应的 ObservableXXXTrigger 的脚本,AddTo 这个 API 就是封装了 ObservableDestroyTrigger
Where,First 过滤
Observable.EveryUpdate().Where(_ => Input.GetMouseButtonDown(0)) //进行一个鼠标是否点击的判断.First() //只获取第一次点击事件.Subscribe(_ =>{Debug.Log("left mouse clicked");});//也可以写成这样
Observable.EveryUpdate().First(_ => Input.GetMouseButtonDown(0)) //只获取第一次点击事件.Subscribe(_ =>{Debug.Log("left mouse clicked");});
EveryUpdate 是事件的发布者。他会每帧会发送⼀个事件过来。
Subscribe 是事件的接收者,接收的是 EveryUpdate 发送的事件。
Where 则是在事件的发布者和接收者之间的⼀个过滤操作。会过滤掉不满⾜条件的事件
First 又进行了一个过滤
Merge
在 UniRx 世界中,任何东西都是以事件流的形式存在,EveryUpdate 和 Timer 都是开启一条事件流。UniRx 可以开启多条事件流,然后使用 Merge 合并。
private void Start()
{var leftClickEvents = Observable.EveryUpdate().Where(_ => Input.GetMouseButtonDown(0));var rightClickEvents = Observable.EveryUpdate().Where(_ => Input.GetMouseButtonDown(1));//点击左键或右键都会触发Observable.Merge(leftClickEvents, rightClickEvents).Subscribe(_ =>{Debug.Log("mouse clicked");});
}
WhenAll
当所有事件流都结束后触发
IEnumerator A()
{yield return new WaitForSeconds(1.0f);Debug.Log("A");
}IEnumerator B()
{yield return new WaitForSeconds(2.0f);Debug.Log("B");
}void Start()
{var aStream = Observable.FromCoroutine(_ => A());var bStream = Observable.FromCoroutine(_ => B());Observable.WhenAll(aStream, bStream).Subscribe(_ =>{Debug.Log("全部处理完");});
}
Start
开启线程
void Start()
{var threadAStream = Observable.Start(() =>{Thread.Sleep(TimeSpan.FromSeconds(1));return 10;});var threadBStream = Observable.Start(() =>{Thread.Sleep(TimeSpan.FromSeconds(3));return 10;});Observable.WhenAll(threadAStream, threadBStream).ObserveOnMainThread() //转到主线程.Subscribe(results =>{Debug.LogFormat("{0}:{1}", results[0], results[1]);});
}
UGUI 支持
public Button button;
public Toggle toggle;
public Image image;
public Slider slider;
public InputField inputField;void Start()
{button.OnClickAsObservable().Subscribe(_ =>{Debug.Log("button clicked");});toggle.OnValueChangedAsObservable().Subscribe(on =>{Debug.LogFormat("toggle value changed: {0}", on);});image.OnDragAsObservable().Subscribe(_ =>{Debug.Log("dragging");});slider.OnValueChangedAsObservable().Subscribe(value =>{Debug.Log("slider: " + value);});inputField.OnValueChangedAsObservable().Subscribe(value =>{Debug.Log("input: " + value);});inputField.OnEndEditAsObservable().Subscribe(value =>{Debug.Log("input: " + value);});
}
查看源码,button.onClick 是 ButtonClickedEvent 类型,而 ButtonClickedEvent 继承自 UnityEvent, button.OnClickAsObservable 是对点击事件进行了封装,同理 UniRx 对其他组件的事件进行了封装
public static IObservable<Unit> OnClickAsObservable(this Button button)
{return button.onClick.AsObservable();
}
public static IObservable<Unit> AsObservable(this UnityEngine.Events.UnityEvent unityEvent)
{return Observable.FromEvent<UnityAction>(h => new UnityAction(h), h => unityEvent.AddListener(h), h => unityEvent.RemoveListener(h));
}
public static IObservable<Unit> FromEvent<TDelegate>(Func<Action, TDelegate> conversion, Action<TDelegate> addHandler, Action<TDelegate> removeHandler)
{return new FromEventObservable<TDelegate>(conversion, addHandler, removeHandler);
}
绑定两个组件
public Toggle mToggle;
public Button mButton;
public Slider mSlider;
public Text mText;void Start()
{// 当 mToggle.isOn = true 时,mButton.interactable = truemToggle.OnValueChangedAsObservable().SubscribeToInteractable(mButton);// 滑动条变化时更新文本mSlider.OnValueChangedAsObservable().SubscribeToText(mText, x => x.ToString());
}
Select
Select 是转换操作符,用于将一个事件源中的值转换成另一个类型的值
public Button buttonA;
public Button buttonB;private void Start()
{// Select将空参数Unit转换为stringbuttonA.OnClickAsObservable().Select(_ => "A").Subscribe(btnId =>{Debug.LogFormat("button {0} clicked", btnId);});buttonB.OnClickAsObservable().Select(_ => "B").Subscribe(btnId =>{Debug.LogFormat("button {0} clicked", btnId);});
}
public ReactiveCollection<int> IntList = new ReactiveCollection<int>();void Start()
{// Select 把每个值进行平方IntList.ObserveAdd().Select(x => x.Value * x.Value).Subscribe(value =>{Debug.Log("add:" + value);});// 添加后触发事件IntList.Add(10);
}
ReactiveProperty(响应式属性)
监听属性的变化,发送通知
// 0 是默认值,可序列化展示在面板上
public IntReactiveProperty Age = new IntReactiveProperty(0);
// 泛型写法,序列化很麻烦
public ReactiveProperty<string> Name = new ReactiveProperty<string>("Tom");void Start()
{Age.Subscribe(age =>{Debug.Log("inner received age changed");});// 赋值后触发事件Age.Value = 10;
}
ReactiveCollection(响应式集合)
ReactiveCollection 类似于 List,监听集合的变化,发送通知
public ReactiveCollection<int> IntList = new ReactiveCollection<int>();void Start()
{IntList.ObserveAdd().Subscribe(value => Debug.Log("add:" + value));IntList.ObserveRemove().Subscribe(value => Debug.Log("remove:" + value));IntList.ObserveCountChanged().Subscribe(count => Debug.Log("count:" + count));// 添加后触发事件IntList.Add(10);
}
ReactiveDictionary(响应式字典)
ReactiveDictionary<string, string> mLanguageCode = new ReactiveDictionary<string, string>
{{"cn","中文"},{"en","英文"}
};void Start()
{mLanguageCode.ObserveAdd().Subscribe(addedLanguage => Debug.LogFormat("add:{0}", addedLanguage));mLanguageCode.ObserveRemove().Subscribe(removedLanguage => Debug.LogFormat("remove:{0}", removedLanguage));mLanguageCode.ObserveCountChanged().Subscribe(count => Debug.LogFormat("count:{0}", count));mLanguageCode.Add("jp", "日文");mLanguageCode.Remove("en");
}
MVP
View 依赖于 Presenter:View通过Presenter来获取数据并处理用户输入。
Presenter 依赖于 View 和 Model:负责处理View和Model之间的交互逻辑。
Model 不依赖于 View 或 Presenter:Model是独立的业务逻辑和数据层,它只负责数据的存储、处理和业务逻辑的实现。当Model的状态发生变化时,它可能会通过回调或事件通知Presenter。
// Presenter
public class EnemyExample : MonoBehaviour
{// Viewpublic Button attackBtn;public Text HPText;EnemyModel mEnemy = new EnemyModel(200);void Start(){// UGUI组件和响应式属性绑定attackBtn.OnClickAsObservable().Subscribe(_ =>{mEnemy.HP.Value -= 99;});mEnemy.HP.SubscribeToText(HPText);mEnemy.IsDead.Where(isDead => isDead).Select(isDead => !isDead).SubscribeToInteractable(attackBtn);}
}// Model
public class EnemyModel
{public ReactiveProperty<long> HP;public IReadOnlyReactiveProperty<bool> IsDead;public EnemyModel(long initialHP){HP = new ReactiveProperty<long>(initialHP);IsDead = HP.Select(hp => hp <= 0).ToReactiveProperty();}
}
ReactiveCommand
用法类似命令模式,ReactiveCommand 实现 IReactiveCommand<T> 接口
public interface IReactiveCommand<T> : IObservable<T>
{IReadOnlyReactiveProperty<bool> CanExecute { get; } //内部使用,外部只读bool Execute(T parameter); //外部调用的
}
当 CanExecute 为 true 时,调用 Execute,Command 才会执行,默认 CanExecute 为 true
void Start()
{// 默认 CanExecute 为 truevar reactiveCommand = new ReactiveCommand();reactiveCommand.Subscribe(_ =>{Debug.Log("每次Execute成功调用后执行");});reactiveCommand.Execute();reactiveCommand.Execute();
}
泛型作为参数
void Start()
{var reactiveCommand = new ReactiveCommand<int>();reactiveCommand.Where(x => x % 2 == 0).Subscribe(x => Debug.LogFormat("{0}是偶数", x));reactiveCommand.Where(x => x % 2 != 0).Timestamp().Subscribe(x => Debug.LogFormat("{0}是奇数,{1}", x.Value, x.Timestamp));reactiveCommand.Execute(10);reactiveCommand.Execute(11);
}
设置事件源
private void Start()
{var mouseDownStream = Observable.EveryUpdate().Where(_ => Input.GetMouseButtonDown(0)).Select(_ => true);var mouseUpStream = Observable.EveryUpdate().Where(_ => Input.GetMouseButtonUp(0)).Select(_ => false);var isMouseUp = Observable.Merge(mouseUpStream, mouseDownStream);// 设置事件源和 CanExecute 为 falsevar reactiveCommand = new ReactiveCommand(isMouseUp, false);reactiveCommand.Subscribe(_ =>{Debug.Log("鼠标按下");});Observable.EveryUpdate().Subscribe(_ =>{reactiveCommand.Execute();});
}
AsyncOperation(异步操作)
加载资源
void Start()
{Resources.LoadAsync<GameObject>("资源名称").AsAsyncOperationObservable().Subscribe(resourceRequest =>{Instantiate(resourceRequest.asset);});
}
加载场景
void Start()
{// 加载进度var progressObservable = new ScheduledNotifier<float>();// 加载 Build Settings 中第 0 个场景SceneManager.LoadSceneAsync(0).AsAsyncOperationObservable(progressObservable).Subscribe(_ =>{Debug.Log("load done");});progressObservable.Subscribe(progress =>{Debug.LogFormat("加载了:{0}%", progress * 100);});
}
类 LINQ 操作符
Distinct
Distinct 意思是清晰的,不同的,用于查询不重复的结果集
List<string> list = new List<string>
{"张三", "张三", "李四"
};list.ToObservable().Distinct().Subscribe(name =>{Debug.Log(name);});
Last
取列表最后一个元素,和 First 相反
class Student
{public string Name;public int Age;
}void Start()
{List<Student> students = new List<Student>{new Student{ Name = "张三", Age = 10 },new Student{ Name = "张三", Age = 15 },new Student{ Name = "李四", Age = 21 },};students.ToObservable().Last(student => student.Name == "张三").Subscribe(student =>{Debug.Log(student.Age);});
}
SelectMany
将一个序列中的每个元素投影到另一个序列,并将这些序列合并为一个单一的序列。具体来说,它会对每个元素进行遍历处理,然后将结果序列合并起来
List<string> list = new List<string>
{"123", "456"
};list.ToObservable().SelectMany(c => c).Subscribe(c =>{Debug.Log(c);});
输出
1
2
3
4
5
6
还可以实现协程的顺序执行
void Start()
{var aStream = Observable.FromCoroutine(A);var bStream = Observable.FromCoroutine(B);aStream.SelectMany(bStream).Subscribe(_ => Debug.Log("A,B结束"));
}IEnumerator A()
{yield return new WaitForSeconds(1f);Debug.Log("A");
}IEnumerator B()
{yield return new WaitForSeconds(1f);Debug.Log("B");
}
未完待续
相关文章:

UniRx 入门
Reactive X 是 Reactive Extensions 的缩写,一般简写为 Rx,最初是 LINQ 的一个扩展,由微软的团队开发,Rx 是一个编程模型,目标是提供一致的编程接口,帮助开发者更方便的处理异步数据流,支持大部…...
简单游戏制作——飞行棋
控制台初始化 int w 50; int h 50; ConsoleInit(w, h); static void ConsoleInit(int w, int h) {//基础设置//光标的隐藏Console.CursorVisible false;//舞台的大小Console.SetWindowSize(w, h);Console.SetBufferSize(w, h); } 场景选择相关 #region 场景选择相关 //声…...
等保一体机
等保一体机是面向等保场景推出的合规型安全防护产品。基于“一个中心,三重防护”的设计理念,通过内置全面、多样的安全能力,为政府、医疗、教育、企业等中小型客户提供快速合规、按需赋能的一站式等保合规解决方案。 等保一体机要求管理网络和…...

什么是寄存器文件(Register File)?
寄存器文件(Register File)是计算机系统中用于存储处理器操作数的小型、快速的存储单元集。它在 CPU 内部,提供极高的访问速度,通常用于存储临时数据、操作数和指令执行过程中的中间结果。 寄存器文件的组成和特点 寄存器集&…...

6月15号作业
使用手动连接,将登录框中的取消按钮使用第二中连接方式,右击转到槽,在该槽函数中,调用关闭函数 将登录按钮使用qt4版本的连接到自定义的槽函数中,在槽函数中判断ui界面上输入的账号是否为"admin"࿰…...

零基础入门学用Arduino 第三部分(三)
重要的内容写在前面: 该系列是以up主太极创客的零基础入门学用Arduino教程为基础制作的学习笔记。个人把这个教程学完之后,整体感觉是很好的,如果有条件的可以先学习一些相关课程,学起来会更加轻松,相关课程有数字电路…...
Trusty qemu + android环境搭建详细步骤
下载源码 mkdir trusty cd trusty repo init -u https://android.googlesource.com/trusty/manifest -b master repo sync -j32 编译 ./trusty/vendor/google/aosp/scripts/build.py generic-arm64 查看编译结果 ls build-root/build-generic-arm64/lk.bin 安装运行依赖 …...
杀戮尖塔游戏
Java 你正在玩策略卡牌杀戮尖塔游戏,轮到你出牌,手里N张攻击卡,每张都需要花金币coust[i]和获得伤害dmager[i]。 最多花3金币能造成的最大伤害是多少? class Solution{public int calc(int[] cost, int[] dmager, N){int[][] db …...
Kubernetes (K8s) 和 Spring Cloud 的区别
Kubernetes (K8s) 和 Spring Cloud 是两种常用的云原生技术,它们在微服务架构和云计算领域中扮演着重要的角色。尽管两者都有助于开发和部署微服务,但它们的功能和目标存在显著差异。本文将详细讨论 Kubernetes 和 Spring Cloud 的区别,从它们…...

定个小目标之刷LeetCode热题(21)
这是道技巧题,利用了 (num - 1)% n 计算下标的形式来将数组元素与数组索引产生映射关系,代码如下,可以看下注释 class Solution {public List<Integer> findDisappearedNumbers(int[] nums) {int n nums.lengt…...

Oracle 打开钱包 ORA-28368: cannot auto-create wallet
ORA-28368: cannot auto-create wallet 开启钱包抱错,看下钱包信息 SQL> select * from v$encryption_wallet;WRL_TYPE -------------------- WRL_PARAMETER -------------------------------------------------------------------------------- STATUS ------…...

【麒麟虚拟机】NetworkManager没有运行
麒麟V10 建linux麒麟虚拟机,发现,网络没有配置 提示,NetworkManager没有运行。编辑联接也不能配置 解决方法,在终端输入命令: sudo systemctl start NetworkManager 启动以后,编辑连接选自动以太网&…...

vue之一键部署的shell脚本和它的点.bat文件、海螺AI、ChatGPT
MENU 前言vite.config.ts的配置deploy文件夹的其他内容remote.shpwd.txtdeploy.bat 前言 1、在src同级新建deploy.bat文件; 2、在src同级新建deploy文件夹,文件夹中新建pwd.txt和remote.sh文件; 3、配置好后,直接双击deploy.bat文…...
pg和oracle的区别
1、从功能上来说pg要比oracle数据库弱。 2、pg不支持索引组织表。 pg和oracle的相似之处: 1、使用共享内存的进程结构,客户端与数据库服务器建立一个连接后,数据库服务器就启动一个进程为这个连接服务。这与mysql的线程模型不一样。 2、p…...

Docker:在DockerHub上创建私有仓库
文章目录 Busybox创建仓库推送镜像到仓库 本篇开始要学习在DockerHub上搭建一个自己的私有仓库 Busybox Busybox是一个集成了三百多个最常用Linux命令和工具的软件,BusyBox包含了很多工具,这里拉取该镜像推送到仓库中: 安装 apt install …...

框架的使用
什么是框架? 盖房子,框架结构 框架结构就是房子主体,基本功能 把很多基础功能已经实现(封装了) 框架:在基础语言之上,对各种基础功能进行封装,方便开发者,提高开发效…...
Autosar-DEM诊断事件管理流程
文章目录 前言一、故障事件监控二、故障信息上报三、故障信息处理Event的使能条件四、故障信息存储五、故障系统降级关联文章:Autosar实践——DEM配置 前言 DEM全称“Diagnostic Event Management”,该模块是AUTOSAR架构中的BSW模块之一。谈到故障,我们首先会想到如何去监控…...

LabVIEW输送机动态特性参数监测系统
开发了一套基于LabVIEW软件和STM32F103ZET6单片机的带式输送机动态特性参数监测系统。该系统通过电阻应变式压力传感器和光电编码器实时采集输送带的张力和带速信息,通过5G模块将数据传输至上位机,实现数据的可视化处理与实时预警,有效提高输…...

绿色版DirectoryOpus功能强大且高度可定制的Windows文件管理器
Directory Opus(通常简称为DOpus)是一款功能强大且高度可定制的Windows文件管理器。它提供了许多超越Windows默认文件资源管理器(Explorer)的功能,使得文件和文件夹的管理变得更加高效和直观。以下是对Directory Opus的…...

Cocos Creator,Youtube 小游戏!
YouTube 官方前段时间发布了一则重磅通知,宣布平台旗下小游戏功能 Youtube Playables 正式登录全平台(安卓、iOS、网页),并内置了数十款精选小游戏。 Youtube Playables 入口: https://www.youtube.com/playables Coco…...

深度学习在微纳光子学中的应用
深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向: 逆向设计 通过神经网络快速预测微纳结构的光学响应,替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...

业务系统对接大模型的基础方案:架构设计与关键步骤
业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...

简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...
在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:
在 HarmonyOS 应用开发中,手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力,既支持点击、长按、拖拽等基础单一手势的精细控制,也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档,…...

关于nvm与node.js
1 安装nvm 安装过程中手动修改 nvm的安装路径, 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解,但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后,通常在该文件中会出现以下配置&…...

【网络安全产品大调研系列】2. 体验漏洞扫描
前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...
蓝桥杯 2024 15届国赛 A组 儿童节快乐
P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡,轻快的音乐在耳边持续回荡,小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下,六一来了。 今天是六一儿童节,小蓝老师为了让大家在节…...

srs linux
下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935,SRS管理页面端口是8080,可…...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...
大模型多显卡多服务器并行计算方法与实践指南
一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...