当前位置: 首页 > news >正文

【Unity入门】热更新框架之xLua

目录

  • 一、xLua概述
    • 1.1xLua简介
    • 1.2xLua安装
  • 二、Lua文件加载
    • 2.1执行字符串
    • 2.2加载Lua文件
    • 2.3自定义loader
  • 三、xLua文件配置
    • 3.1打标签
    • 3.2静态列表
    • 3.3动态列表
  • 四、Lua与C#交互
    • 4.1 C#访问Lua
      • 4.1.1 获取一个全局基本数据类型
      • 4.1.2 访问一个全局的table
      • 4.1.3 访问一个全局的function
    • 4.2 Lua调用C#
      • 4.2.1 new C#对象
      • 4.2.2 访问C#静态属性,方法
      • 4.2.3 访问C#成员属性,方法
      • 4.2.4 访问父类属性,方法
      • 4.2.5 参数的输入输出属性(out,ref)
      • 4.2.6 重载方法
      • 4.2.7 操作符
      • 4.2.8 参数带默认值的方法
      • 4.2.9 可变参数方法
      • 4.2.10 使用Extension methods
      • 4.2.11 泛化(模版)方法
      • 4.2.12 枚举类型
      • 4.2.13 delegate使用(调用,+,-)
      • 4.2.14 event
      • 4.2.15 C#复杂类型和table的自动转换
      • 4.2.16 “强”转
      • 4.2.17 C#与Lua交互原理
  • 五、xLua热更新
    • 5.1 使用方式
    • 5.2 约束
    • 5.3 API
    • 5.4 Hotfix Flag
    • 5.5 使用建议
  • 六、热更新大致流程

一、xLua概述

1.1xLua简介

xLua是由腾讯维护的一个开源项目,xLua为Unity、 .Net、 Mono等C#环境增加Lua脚本编程的能力,借助xLua,这些Lua代码可以方便的和C#相互调用。自2016年初推广以来,已经应用于十多款腾讯自研游戏,因其良好性能、易用性、扩展性而广受好评。现在,腾讯已经将xLua开源到GitHub。
git下载地址:https://github.com/Tencent/xLua
xLua教程地址:https://github.com/Tencent/xLua/blob/master/Assets/XLua/Doc/XLua%E6%95%99%E7%A8%8B.md

xLua在功能、性能、易用性都有不少突破,这几方面分别最具代表性的是:

  1. 可以运行时把C#实现(方法,操作符,属性,事件等等)替换成lua实现;
  2. 出色的GC优化,自定义struct,枚举在Lua和C#间传递无C# gc alloc;
  3. 编辑器下无需生成代码,开发更轻量;

除此之外,xLua另一特色功能就是代码热补丁。非常适合前期没有规划使用Lua进行逻辑开发,后期又需要在iOS这种平台获得代码热更新能力的项目。

1.2xLua安装

  1. 首先下载最新版xLua ,然后解压到你想解压到的位置;
    在这里插入图片描述

  2. xLua-master工程打开后,你将会看到一个Assets目录,点击到Assets目录会看到以下几个文件
    ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/903d2e6a80a24917a0f6d8c4f2ddc595.png
    将 xLua-master 工程中Assets目录下的文件复制到你的Unity工程的Assets目录下即可;
    在这里插入图片描述

  3. 加载完后,菜单栏有 xlua 菜单表示,导入成功
    在这里插入图片描述

  4. 在菜单栏中 xlua 菜单添加 Hotfix Inject In Editor 选项
    在这里插入图片描述
    菜单栏中 xlua 菜单会显示 Hotfix Inject In Editor 选项
    在这里插入图片描述

  5. 如果希望安装到其它目录,可参看:https://github.com/Tencent/xLua/blob/master/Assets/XLua/Doc/faq.md

  6. xLua API可参见链接:https://github.com/Tencent/xLua/blob/master/Assets/XLua/Doc/XLua_API.md

示例代码:

using UnityEngine;
//引入 Xlua 命名空间
using XLua;public class HotFixScript : MonoBehaviour
{//lua 环境变量private LuaEnv luaEnv;private void Start(){//创建lua运行环境luaEnv = new LuaEnv();luaEnv.DoString("print('Hellow World 1')");}private void OnDestroy(){//释放lua环境luaEnv.Dispose();}
}

编写完脚本,挂载到游戏物体上,先按 Generate Code 选项生成代码,再按 Hotfix Inject In Editor 选项将补丁注入编辑器,运行结果:
在这里插入图片描述

二、Lua文件加载

2.1执行字符串

最基本是直接用LuaEnv.DoString执行一个字符串,当然,字符串得符合Lua语法

比如:luaenv.DoString(“print(‘hello world’)”)

完整代码见XLua\Tutorial\LoadLuaScript\ByString目录。

但这种方式并不建议,更建议下面介绍这种方法加载Lua文件。

2.2加载Lua文件

用lua的require函数即可,比如:DoString(“require ‘byfile’")

require实际上是调一个个的loader去加载,有一个成功就不再往下尝试,全失败则报文件找不到。

完整代码见XLua\Tutorial\LoadLuaScript\ByFile目录。

2.3自定义loader

在xLua加自定义loader是很简单的,只涉及到一个接口:

public delegate byte[] CustomLoader(ref string filepath);

public void LuaEnv.AddLoader(CustomLoader loader);

通过AddLoader可以注册个回调,该回调参数是字符串,lua代码里头调用require时,参数将会透传给回调,回调中就可以根据这个参数去加载指定文件,如果需要支持调试,需要把filepath修改为真实路径传出。该回调返回值是一个byte数组,如果为空表示该loader找不到,否则则为lua文件的内容。

有了这个就简单了,用IIPS的IFS?没问题。写个loader调用IIPS的接口读文件内容即可。文件已经加密?没问题,自己写loader读取文件解密后返回即可。
示例代码:

using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;
using XLua;public class LuaStudy : MonoBehaviour
{private LuaEnv luaEnv;private void Start(){//创建lua运行环境luaEnv = new LuaEnv();LuaLoaderFun();VisitLua_Table();VisitLua_Function();}private void OnDestroy(){//释放lua环境luaEnv.Dispose();}/// <summary>/// 加载及调用lua脚本/// </summary>void LuaLoaderFun(){//执行lua的输出语句luaEnv.DoString("print('Hellow World 1')");//在lua中调用C#方法luaEnv.DoString("CS.UnityEngine.Debug.Log('Hellow World 2')");//加载运行Resources文件中的lua脚本TextAsset ta = Resources.Load<TextAsset>("HellowWorld.lua");luaEnv.DoString(ta.text);//加载运行helloworld.lua.txt  默认从Resources文件中进行加载luaEnv.DoString("require 'HellowWorld'");// 添加自定义的Loader方法//添加了一个自定义的Loader返回null并且DoString里面添加的是一个不存在的lua文件。它会返回错误。//luaEnv.AddLoader(MyLoader_1);//luaEnv.DoString("require 'xxx'");// 添加自定义的Loader方法//添加了一个自定义的Loader返回lua语句的二进制并且DoString里面添加的是一个不存在的lua文件。它会执行自定义的Loader的输出。//luaEnv.AddLoader(MyLoader_2);//luaEnv.DoString("require 'xxx'");//通过自定义Loader加载指定目录的Lua脚本luaEnv.AddLoader(MyLoader_3);luaEnv.DoString("require 'Lua_StreamingAssets'");}/// <summary>/// 访问获取lua属性和表/// </summary>void VisitLua_Table() {//调用lua脚本才能访问属性luaEnv.DoString("require 'LuaTest'");//获取lua脚本中的全局变量int num = luaEnv.Global.Get<int>("num");//获取lua里面的全局变量numstring name = luaEnv.Global.Get<string>("name");//获取lua里面的全局变量nameDebug.Log("num:" + num + "  name:" + name);//访问lua中的table(映射到class)Person personTemp = luaEnv.Global.Get<Person>("person");Debug.Log(personTemp.name + "    " + personTemp.age);//这种方式的访问,修改age的值不会影响到lua里面的表的属性personTemp.name = "wang";personTemp.age = 50;//修改后试一下Person personTemp2 = luaEnv.Global.Get<Person>("person");Debug.Log(personTemp2.name + "    " + personTemp2.age);//访问lua中的table(映射到interface)//映射到interface修改p中的属性,lua中的原table也会发生变化IPerson personTemp3 = luaEnv.Global.Get<IPerson>("person");Debug.Log(personTemp2.name + "    " + personTemp2.age);//通过LuaTable访问tableList<object> list = luaEnv.Global.Get<List<object>>("person");foreach (object o in list){print(o);}//通过LuaTable类 比较慢LuaTable luaTable = luaEnv.Global.Get<LuaTable>("person");print(luaTable.Get<string>("name"));print(luaTable.Get<int>("age"));}/// <summary>/// 访问lua中的全局方法/// </summary>void VisitLua_Function(){//调用lua脚本才能访问属性luaEnv.DoString("require 'LuaTest'");//使用委托来获取Lua中的全局函数Add add = luaEnv.Global.Get<Add>("add");add(2, 4);//通过LuaFunction访问Lua中的全局函数LuaFunction luaFunction = luaEnv.Global.Get<LuaFunction>("add");luaFunction.Call(2, 4);}private byte[] MyLoader_1(ref string filePath){print(filePath);return null;}private byte[] MyLoader_2(ref string filePath) {string s = "print(123)";return System.Text.Encoding.UTF8.GetBytes(s);}private byte[] MyLoader_3(ref string filePath) {string path = Application.streamingAssetsPath + "/" + filePath + ".lua.txt";return System.Text.Encoding.UTF8.GetBytes(File.ReadAllText(path));}class Person{public string name;public int age;}//打标签[CSharpCallLua]public interface IPerson{string name { get; set; }int age { get; set; }}//打标签[CSharpCallLua]delegate void Add(int a, int b);}

完整示例见XLua\Tutorial\LoadLuaScript\Loader。

三、xLua文件配置

xLua所有的配置都支持三种方式:打标签;静态列表;动态列表。
配置有两必须两建议:

  • 列表方式均必须是静态的字段/属性
  • 列表方式均必须放置一个静态类
  • 建议使用标签方式
  • 建议列表方式配置放Editor目录(如果是Hotfix配置, - - 并且类位于Assembly-CSharp.dll之外的其他dll,必须放Editor目录)

3.1打标签

xLua用白名单来指明生成哪些代码,而白名单通过attribute来配置,比如你想从lua

调用c#的某个类,希望生成适配代码,你可以为这个类型打一个LuaCallCSharp标签:

[LuaCallCSharp]
publicclassA
{}

该方式方便,但在il2cpp下会增加不少的代码量,不建议使用。

常用标签如下所示:

  1. [XLua.LuaCallCSharp]:为一个C#类型加了这个配置,xLua会生成这个类型的适配代码(否则将会尝试用性能较低的反射方式来访问),提供给Lua调用。

  2. [XLua.CSharpCallLua]:如果希望Lua文件中的逻辑能够被C#调用,可为Lua重的函数等打上该标签。

  3. [XLua.Hotfix]:用于标记需要进行热更新的文件。

除此之外,xLua还提供了其他标签,具体可参见链接:https://github.com/Tencent/xLua/blob/master/Assets/XLua/Doc/configure.md

3.2静态列表

有时我们无法直接给一个类型打标签,比如系统api,没有源码的库,或者实例化的泛化类型,那么你可以在一个静态类里声明一个静态字段,该字段的类型除BlackList和AdditionalProperties之外只要实现了IEnumerable就可以了(这两个例外后面具体会说),然后为这字段加上标签:

[LuaCallCSharp]
public static List<Type> mymodule_lua_call_cs_list = new List<Type>()
{typeof(GameObject),typeof(Dictionary<string, int>),
};

该字段需要放置一个静态类里头,建议放置Editor目录。

3.3动态列表

声明一个静态属性,打上相应的标签即可。

[Hotfix]
public static List<Type> by_property
{get{return (from type in Assembly.Load("Assembly-CSharp").GetTypes()where type.Namespace == "XXXX"select type).ToList();}
}

Getter是代码,你可以实现很多效果,比如按名称空间配置,按程序集配置等等。

该属性需要放置一个静态类里头,建议放置Editor目录。

四、Lua与C#交互

4.1 C#访问Lua

4.1.1 获取一个全局基本数据类型

访问LuaEnv.Global就可以了,上面有个模版Get方法,可指定返回的类型。

luaenv.Global.Get<int>("a")
luaenv.Global.Get<string>("b")
luaenv.Global.Get<bool>("c")

4.1.2 访问一个全局的table

1、映射到普通class或struct

定义一个class,有对应于table的字段的public属性,而且有无参数构造函数即可,比如对于{f1 = 100, f2 = 100}可以定义一个包含public int f1;public int f2;的class。这种方式下xLua会帮你new一个实例,并把对应的字段赋值过去。table的属性可以多于或者少于class的属性。可以嵌套其它复杂类型。

要注意的是,这个过程是值拷贝,如果class比较复杂代价会比较大。而且修改class的字段值不会同步到table,反过来也不会。这个功能可以通过把类型加到GCOptimize生成降低开销。

2、映射到一个interface

这种方式依赖于生成代码(如果没生成代码会抛InvalidCastException异常),代码生成器会生成这个interface的实例,如果get一个属性,生成代码会get对应的table字段,如果set属性也会设置对应的字段。甚至可以通过interface的方法访问lua的函数。

3、更轻量级的by value方式:映射到Dictionary<>,List<>

不想定义class或者interface的话,可以考虑用这个,前提table下key和value的类型都是一致的。

4、另外一种by ref方式:映射到LuaTable类

这种方式好处是不需要生成代码,但也有一些问题,比如慢,比方式2要慢一个数量级,比如没有类型检查。

4.1.3 访问一个全局的function

1、映射到delegate

这种是建议的方式,性能好很多,而且类型安全。缺点是要生成代码(如果没生成代码会抛InvalidCastException异常)。

delegate要怎样声明呢?

对于function的每个参数就声明一个输入类型的参数。

多返回值要怎么处理?从左往右映射到c#的输出参数,输出参数包括返回值,out参数,ref参数。

参数、返回值类型支持哪些呢?都支持,各种复杂类型,out,ref修饰的,甚至可以返回另外一个delegate。

delegate的使用就更简单了,直接像个函数那样用就可以了。

2、映射到LuaFunction

这种方式的优缺点刚好和第一种相反。

使用也简单,LuaFunction上有个变参的Call函数,可以传任意类型,任意个数的参数,返回值是object的数组,对应于lua的多返回值。

4.2 Lua调用C#

4.2.1 new C#对象

在C#这样new一个对象:

var newGameObj = new UnityEngine.GameObject();

对应到Lua是这样:

local newGameObj = CS.UnityEngine.GameObject()

基本类似,除了:

lua里头没有new关键字;

所有C#相关的都放到CS下,包括构造函数,静态成员属性、方法;

如果有多个构造函数呢?放心,xlua支持重载,比如你要调用GameObject的带一个string参数的构造函数,这么写:

local newGameObj2 = CS.UnityEngine.GameObject('helloworld')

4.2.2 访问C#静态属性,方法

读静态属性

CS.UnityEngine.Time.deltaTime

写静态属性

CS.UnityEngine.Time.timeScale = 0.5

调用静态方法

CS.UnityEngine.GameObject.Find('helloworld')

小技巧:如果需要经常访问的类,可以先用局部变量引用后访问,除了减少敲代码的时间,还能提高性能:

local GameObject = CS.UnityEngine.GameObject
GameObject.Find('helloworld')

4.2.3 访问C#成员属性,方法

读成员属性

testobj.DMF

写成员属性

testobj.DMF = 1024

调用成员方法

注意:调用成员方法,第一个参数需要传该对象,建议用冒号语法糖,如下

testobj:DMFunc()

4.2.4 访问父类属性,方法

xlua支持(通过派生类)访问基类的静态属性,静态方法,(通过派生类实例)访问基

类的成员属性,成员方法。

4.2.5 参数的输入输出属性(out,ref)

Lua调用测的参数处理规则:C#的普通参数算一个输入形参,ref修饰的算一个输入形参

out修饰的不算,然后从左往右对应lua 调用测的实参列表;

Lua调用测的返回值处理规则:C#函数的返回值(如果有的话)算一个返回值,out算一个返回值,ref算一个返回值,然后从左往右对应lua的多返回值。

4.2.6 重载方法

直接通过不同的参数类型进行重载函数的访问,例如:

testobj:TestFunc(100)

testobj:TestFunc(‘hello’)

将分别访问整数参数的TestFunc和字符串参数的TestFunc。

注意:xlua只一定程度上支持重载函数的调用,因为lua的类型远远不如C#丰富,存在一

对多的情况,比如C#的int,float,double都对应于lua的number,上面的例子中

TestFunc如果有这些重载参数,第一行将无法区分开来,只能调用到其中一个(生成代码

中排前面的那个)。

4.2.7 操作符

支持的操作符有:+,-,*,/,==,一元 -,<,<=, %,[]

4.2.8 参数带默认值的方法

和C#调用有默认值参数的函数一样,如果所给的实参少于形参,则会用默认值补上。

4.2.9 可变参数方法

对于C#的如下方法:

void VariableParamsFunc(int a, params string[] strs)

可以在lua里头这样调用:

testobj:VariableParamsFunc(5, 'hello', 'john')

4.2.10 使用Extension methods

在C#里定义了,lua里就能直接使用。

4.2.11 泛化(模版)方法

不直接支持,可以通过Extension methods功能进行封装后调用。

4.2.12 枚举类型

枚举值就像枚举类型下的静态属性一样。

testobj:EnumTestFunc(CS.Tutorial.TestEnum.E1)

上面的EnumTestFunc函数参数是Tutorial.TestEnum类型的

另外,如果枚举类加入到生成代码的话,枚举类将支持__CastFrom方法,可以实现从一个整数或者字符串到枚举值的转换,例如:

CS.Tutorial.TestEnum.__CastFrom(1)

CS.Tutorial.TestEnum.__CastFrom(‘E1’)

4.2.13 delegate使用(调用,+,-)

C#的delegate调用:和调用普通lua函数一样

+操作符:对应C#的+操作符,把两个调用串成一个调用链,右操作数可以是同类型的

C#delegate或者是lua函数。

-操作符:和+相反,把一个delegate从调用链中移除。

Ps:delegate属性可以用一个luafunction来赋值。

4.2.14 event

比如testobj里头有个事件定义是这样:public event Action TestEvent;

增加事件回调

testobj:TestEvent(‘+’, lua_event_callback)

移除事件回调

testobj:TestEvent(‘-’, lua_event_callback)

4.2.15 C#复杂类型和table的自动转换

对于一个有无参构造函数的C#复杂类型,在lua侧可以直接用一个table来代替,该table对应复杂类型的public字段有相应字段即可,支持函数参数传递,属性赋值等,例如:

C#下B结构体(class也支持)定义如下:

public struct A{ public int a;}

public struct B{ public A b; public double c;}

某个类有成员函数如下:void Foo(B b)

在lua可以这么调用:

obj:Foo({b = {a = 100}, c = 200})

获取类型(相当于C#的typeof)

比如要获取UnityEngine.ParticleSystem类的Type信息,可以这样

typeof(CS.UnityEngine.ParticleSystem)。

4.2.16 “强”转

lua没类型,所以不会有强类型语言的“强转”,但有个有点像的东西:告诉xlua要用指定的生成代码去调用一个对象,这在什么情况下能用到呢?有的时候第三方库对外暴露的是一个interface或者抽象类,实现类是隐藏的,这样我们无法对实现类进行代码生成。该实现类将会被xlua识别为未生成代码而用反射来访问,如果这个调用是很频繁的话还是很影响性能的,这时我们就可以把这个interface或者抽象类加到生成代码,然后指定用该生成代码来访问:

cast(calc, typeof(CS.Tutorial.Calc))

上面就是指定用CS.Tutorial.Calc的生成代码来访问calc对象。

4.2.17 C#与Lua交互原理

1、C#调用Lua:C#先调用Lua的dll文件(C语言写的库),dll文件执行Lua代码

2、Lua调用C#:

1、Wrap方式:非反射机制,需要为源文件生成相应的wrap文件,当启动

Lua虚拟机时,Wrap文件将会被自动注册到Lua虚拟机中,之后,Lua文件

将能够识别和调用C#源文件。

总结:Lua调用Wrap文件, Wrap文件调用C#源文件

2、反射机制

五、xLua热更新

5.1 使用方式

  1. 添加HOTFIX_ENABLE宏打开该特性(在Unity3D的File->Build Setting->Scripting Define Symbols下添加)。编辑器、各手机平台这个宏要分别设置!如果是自动化打包,要注意在代码里头用API设置的宏是不生效的,需要在编辑器设置。(建议平时开发业务代码不打开HOTFIX_ENABLE,只在build手机版本或者要在编译器下开发补丁时打开HOTFIX_ENABLE)

  2. 执行XLua/Generate Code菜单。

  3. 注入,构建手机包这个步骤会在构建时自动进行,编辑器下开发补丁需要手动执行"XLua/Hotfix Inject In Editor"菜单。注入成功会打印“hotfix inject finish!”或者“had injected!”。

5.2 约束

不支持静态构造函数,目前只支持Assets下代码的热补丁,不支持引擎,c#系统库的热补丁。

5.3 API

  1. xlua.hotfix(class, [method_name], fix)
    描述 : 注入lua补丁
  • class : C#类,两种表示方法,CS.Namespace.TypeName或者字符串方式"Namespace.TypeName",字符串格式和C#的Type.GetType要求一致,如果是内嵌类型(Nested Type)是非Public类型的话,只能用字符串方式表示"Namespace.TypeName+NestedTypeName";
  • method_name : 方法名,可选;
  • fix : 如果传了method_name,fix将会是一个function,否则通过table提供一组函数。table的组织按key是method_name,value是function的方式。

base(csobj)
描述 : 子类override函数通过base调用父类实现。
csobj : 对象
返回值 : 新对象,可以通过该对象base上的方法

  1. util.hotfix_ex(class, method_name, fix)
    描述 : xlua.hotfix的增强版本,可以在fix函数里头执行原来的函数,缺点是fix的执行会略慢。
  • method_name : 方法名;
  • fix : 用来替换C#方法的lua function。

5.4 Hotfix Flag

Hotfix标签可以设置一些标志位对生成代码及插桩定制化。

Stateless、Stateful
遗留设置,Stateful方式在新版本已经删除,因为这种方式可以用xlua.util.hotfix_state接口达到类似的效果。

ValueTypeBoxing
值类型的适配delegate会收敛到object,好处是代码量更少,不好的是值类型会产生boxing及gc,适用于对text段敏感的业务。

IgnoreProperty
不对属性注入及生成适配代码,一般而言,大多数属性的实现都很简单,出错几率比较小,建议不注入。

IgnoreNotPublic
不对非public的方法注入及生成适配代码。除了像MonoBehaviour那种会被反射调用的私有方法必须得注入,其它仅被本类调用的非public方法可以不注入,只不过修复时会工作量稍大,所有引用到这个函数的public方法都要重写。

Inline
不生成适配delegate,直接在函数体注入处理代码。

IntKey
不生成静态字段,而是把所有注入点放到一个数组集中管理。

5.5 使用建议

对所有较大可能变动的类型加上Hotfix标识;
建议用反射找出所有函数参数、字段、属性、事件涉及的delegate类型,标注CSharpCallLua;
业务代码、引擎API、系统API,需要在Lua补丁里头高性能访问的类型,加上
LuaCallCSharp

引擎API、系统API可能被代码剪裁调(C#无引用的地方都会被剪裁),如果觉得可能会
新增C#代码之外的API调用,这些API所在的类型要么加LuaCallCSharp,要么ReflectionUse;

六、热更新大致流程

  1. 游戏一开始启动时,检查远程服务器上是否有新的myHotfix.lua文件(例如:md5比对,自己加解密),有的话,下载下来,放在指定目录,没有的话,读取本地已有的myHotfix.lua文件,若文件不存在,则说明不需要热修复,一般这种情况是在项目刚发布的早期,没有进行打补丁;
  2. 项目发布版本前,需要在CustomGenConfig.cs中 加入需要添加[Hotfix]标签的类型,想要更灵活使用的话,可以自己写个配置表,读取配置中的类型,自动添加,***只有加入[Hotfix]标签的类型,才可以调用xlua.hotfix()。

相关文章:

【Unity入门】热更新框架之xLua

目录 一、xLua概述1.1xLua简介1.2xLua安装 二、Lua文件加载2.1执行字符串2.2加载Lua文件2.3自定义loader 三、xLua文件配置3.1打标签3.2静态列表3.3动态列表 四、Lua与C#交互4.1 C#访问Lua4.1.1 获取一个全局基本数据类型4.1.2 访问一个全局的table4.1.3 访问一个全局的functio…...

大数据Doris(四十五):物化视图选择最优

文章目录 物化视图选择最优 物化视图选择最优 下面详细解释一下第一步最优物化视图是被如何选择出来的。 这里分为两个步骤: 对候选集合进行一个过滤。只要是查询的结果能从物化视图数据计算(取部分行,部分列,或部分行列的聚合)出都可以留在候选集中,过滤完成后候选集合…...

PostgreSQL10数据库源码安装及plpython2u、uuid-ossp插件安装

PostgreSQL10数据库源码安装及plpython2u、uuid-ossp插件安装 1、环境2、安装包下载3、安装3.1 、解压3.2、配置3.3、编译安装3.4 、启动与关闭 4、安装 uuid-ossp 、plpython2u插件5、参考 1、环境 centos 7 、 postgresql 10.19 2、安装包下载 postgres 源码安装包 3、安…...

如何成为ChatGPT 优质Prompt创作者

如何提问&#xff1f; 我想让你成为我的Prompt创作者。你的目标是帮助我创作最佳的Prompt&#xff0c;这个Prompt将由你ChatGPT使用。你将遵循 以下过程&#xff1a;1.首先&#xff0c;你会问我Prompt是关于什么&#xff1f;我会告诉你&#xff0c;但我们需要 通过不断的重复来…...

LeetCode第71题 - 简化路径

题目 以 Unix 风格给出一个文件的绝对路径&#xff0c;你需要简化它。或者换句话说&#xff0c;将其转换为规范路径。 在 Unix 风格的文件系统中&#xff0c;一个点&#xff08;.&#xff09;表示当前目录本身&#xff1b;此外&#xff0c;两个点 &#xff08;…&#xff09; 表…...

VSCode上远程调试代码出现的问题

记录一下&#xff1a; 真的是汗流浃背了&#xff0c;师妹叫帮忙如何在VSCode上远程调试代码&#xff0c;一些自己已经经历过的问题&#xff0c;现在已经忘记了。又在网上一顿搜索&#xff0c;这次记录下吧。。。 出现以下问题&#xff1a; 1. 终端界面总是sh-4.4 $ &#xff…...

【langchain】入门初探实战笔记(Chain, Retrieve, Memory, Agent)

1. 简介 1.1 大语言模型技术栈 大语言模型技术栈由四个主要部分组成&#xff1a; 数据预处理流程&#xff08;data preprocessing pipeline&#xff09;嵌入端点&#xff08;embeddings endpoint &#xff09;向量存储&#xff08;vector store&#xff09;LLM 终端&#xff…...

《数据结构、算法与应用C++语言描述》- 平衡搜索树 -全网唯一完整详细实现插入和删除操作的模板类

平衡搜索树 完整可编译运行代码见&#xff1a;Github::Data-Structures-Algorithms-and-Applications/_34Balanced search tree 概述 本章会讲AVL、红-黑树、分裂树、B-树。 平衡搜索树的应用&#xff1f; AVL 和红-黑树和分裂树适合内部存储的应用。 B-树适合外部存储的…...

网络路由跟踪工具

随着企业网络需求的增长&#xff0c;组织发现监控和管理其网络基础设施变得越来越困难。网络管理员正在转向其他工具和资源&#xff0c;这些工具和资源可以使他们的工作更轻松一些&#xff0c;尤其是在故障排除方面。 目前&#xff0c;网络管理员主要使用简单、免费提供的实用…...

设计模式 七大原则

1.单一职责原则 单一职责原则&#xff08;SRP&#xff1a;Single responsibility principle&#xff09;又称单一功能原则 核心&#xff1a;解耦和增强内聚性&#xff08;高内聚&#xff0c;低耦合&#xff09;。 描述&#xff1a; 类被修改的几率很大&#xff0c;因此应该专注…...

(1)(1.13) SiK无线电高级配置(一)

文章目录 前言 1 监控链接质量 2 诊断范围问题 3 MAVLink协议说明 前言 本文提供 SiK 遥测无线电(SiK Telemetry Radio)的高级配置信息。它面向"高级用户"和希望更好地了解无线电如何运行的用户。 &#xff01;Tip 大多数用户只需要 SiK Radio v2 中提供的基本…...

drf知识--10

接口文档 # 后端把接口写好后&#xff1a; 登录接口&#xff1a;/api/v1/login ---> post---name pwd 注册接口 查询所有图书带过滤接口 # 前后端需要做对接&#xff0c;对接第一个东西就是这个接口文档&#xff0c;前端照着接口文档开发 公司3个人&#xff…...

探索 Vue 实例方法的魅力:提升 Vue 开发技能(下)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…...

mysql死锁排查

查看正在进行中的事务 SELECT * FROM information_schema.INNODB_TRX;字段解释trx_id唯一事务id号&#xff0c;只读事务和非锁事务是不会创建id的trx_state事务的执行状态&#xff0c;值一般分为&#xff1a;RUNNING, LOCK WAIT, ROLLING BACK, and COMMITTING.trx_started事务…...

若依项目(ruoy-vue)多模块依赖情况简要分析

主pom文件关键点分析 properties标签声明变量信息&#xff1a;版本号、编码类型、java版本spring-boot依赖形式&#xff1a;spring-boot-dependencies、pom、importdependencies中添加本项目内部模块&#xff0c;同时在modules中声明模块packaging打包选择pom设置打包maven-co…...

【普中开发板】基于51单片机的篮球计分器液晶LCD1602显示( proteus仿真+程序+设计报告+讲解视频)

基于普中开发板51单片机的篮球计分器液晶LCD1602显示 1.主要功能&#xff1a;讲解视频&#xff1a;2.仿真3. 程序代码4. 设计报告5. 设计资料内容清单&&下载链接资料下载链接&#xff08;可点击&#xff09;&#xff1a; 基于51单片机的篮球计分器液晶LCD1602显示 ( pr…...

按照层次遍历结果打印完全二叉树

按照层次遍历结果打印完全二叉树 按照推论结果&#xff1a; l 层首个节点位置 2h-l - 1l 层节点间距&#xff1a;2h-l1 - 1 编码实现 public static<E> void print(BinaryTree<E> tree) {List<List<Node<E>>> levelNodeList levelOrderTraver…...

基于SpringBoot的药店管理系统

文章目录 项目介绍主要功能截图:部分代码展示设计总结项目获取方式🍅 作者主页:超级无敌暴龙战士塔塔开 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅 项目介绍 基于SpringBoot的药店管理系统,java项目…...

Java 泛型深入解析

Java 中的泛型是一种强大的编程特性&#xff0c;允许我们编写更加通用和类型安全的代码。本篇博客将深入探讨 Java 泛型的各个方面&#xff0c;包括泛型类、泛型方法、泛型接口以及泛型通配符。 1. 泛型类 首先&#xff0c;让我们看一个简单的泛型类的例子。在下面的代码中&a…...

Apache Doris (六十): Doris - 物化视图

🏡 个人主页:IT贫道_大数据OLAP体系技术栈,Apache Doris,Clickhouse 技术-CSDN博客 🚩 私聊博主:加入大数据技术讨论群聊,获取更多大数据资料。 🔔 博主个人B栈地址:豹哥教你学编程的个人空间-豹哥教你学编程个人主页-哔哩哔哩视频 目录...

KubeSphere 容器平台高可用:环境搭建与可视化操作指南

Linux_k8s篇 欢迎来到Linux的世界&#xff0c;看笔记好好学多敲多打&#xff0c;每个人都是大神&#xff01; 题目&#xff1a;KubeSphere 容器平台高可用&#xff1a;环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现

目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

HTML 语义化

目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案&#xff1a; 语义化标签&#xff1a; <header>&#xff1a;页头<nav>&#xff1a;导航<main>&#xff1a;主要内容<article>&#x…...

Flask RESTful 示例

目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题&#xff1a; 下面创建一个简单的Flask RESTful API示例。首先&#xff0c;我们需要创建环境&#xff0c;安装必要的依赖&#xff0c;然后…...

微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】

微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来&#xff0c;Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案

问题描述&#xff1a;iview使用table 中type: "index",分页之后 &#xff0c;索引还是从1开始&#xff0c;试过绑定后台返回数据的id, 这种方法可行&#xff0c;就是后台返回数据的每个页面id都不完全是按照从1开始的升序&#xff0c;因此百度了下&#xff0c;找到了…...

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...

OpenLayers 分屏对比(地图联动)

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能&#xff0c;和卷帘图层不一样的是&#xff0c;分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)

Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败&#xff0c;具体原因是客户端发送了密码认证请求&#xff0c;但Redis服务器未设置密码 1.为Redis设置密码&#xff08;匹配客户端配置&#xff09; 步骤&#xff1a; 1&#xff09;.修…...

Springboot社区养老保险系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;社区养老保险系统小程序被用户普遍使用&#xff0c;为方…...