【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在功能、性能、易用性都有不少突破,这几方面分别最具代表性的是:
- 可以运行时把C#实现(方法,操作符,属性,事件等等)替换成lua实现;
- 出色的GC优化,自定义struct,枚举在Lua和C#间传递无C# gc alloc;
- 编辑器下无需生成代码,开发更轻量;
除此之外,xLua另一特色功能就是代码热补丁。非常适合前期没有规划使用Lua进行逻辑开发,后期又需要在iOS这种平台获得代码热更新能力的项目。
1.2xLua安装
-
首先下载最新版xLua ,然后解压到你想解压到的位置;
-
xLua-master工程打开后,你将会看到一个Assets目录,点击到Assets目录会看到以下几个文件
将 xLua-master 工程中Assets目录下的文件复制到你的Unity工程的Assets目录下即可;
-
加载完后,菜单栏有 xlua 菜单表示,导入成功
-
在菜单栏中 xlua 菜单添加 Hotfix Inject In Editor 选项
菜单栏中 xlua 菜单会显示 Hotfix Inject In Editor 选项
-
如果希望安装到其它目录,可参看:https://github.com/Tencent/xLua/blob/master/Assets/XLua/Doc/faq.md
-
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下会增加不少的代码量,不建议使用。
常用标签如下所示:
-
[XLua.LuaCallCSharp]:为一个C#类型加了这个配置,xLua会生成这个类型的适配代码(否则将会尝试用性能较低的反射方式来访问),提供给Lua调用。
-
[XLua.CSharpCallLua]:如果希望Lua文件中的逻辑能够被C#调用,可为Lua重的函数等打上该标签。
-
[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 使用方式
-
添加HOTFIX_ENABLE宏打开该特性(在Unity3D的File->Build Setting->Scripting Define Symbols下添加)。编辑器、各手机平台这个宏要分别设置!如果是自动化打包,要注意在代码里头用API设置的宏是不生效的,需要在编辑器设置。(建议平时开发业务代码不打开HOTFIX_ENABLE,只在build手机版本或者要在编译器下开发补丁时打开HOTFIX_ENABLE)
-
执行XLua/Generate Code菜单。
-
注入,构建手机包这个步骤会在构建时自动进行,编辑器下开发补丁需要手动执行"XLua/Hotfix Inject In Editor"菜单。注入成功会打印“hotfix inject finish!”或者“had injected!”。
5.2 约束
不支持静态构造函数,目前只支持Assets下代码的热补丁,不支持引擎,c#系统库的热补丁。
5.3 API
- 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上的方法
- 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;
六、热更新大致流程
- 游戏一开始启动时,检查远程服务器上是否有新的myHotfix.lua文件(例如:md5比对,自己加解密),有的话,下载下来,放在指定目录,没有的话,读取本地已有的myHotfix.lua文件,若文件不存在,则说明不需要热修复,一般这种情况是在项目刚发布的早期,没有进行打补丁;
- 项目发布版本前,需要在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创作者
如何提问? 我想让你成为我的Prompt创作者。你的目标是帮助我创作最佳的Prompt,这个Prompt将由你ChatGPT使用。你将遵循 以下过程:1.首先,你会问我Prompt是关于什么?我会告诉你,但我们需要 通过不断的重复来…...
LeetCode第71题 - 简化路径
题目 以 Unix 风格给出一个文件的绝对路径,你需要简化它。或者换句话说,将其转换为规范路径。 在 Unix 风格的文件系统中,一个点(.)表示当前目录本身;此外,两个点 (…) 表…...
VSCode上远程调试代码出现的问题
记录一下: 真的是汗流浃背了,师妹叫帮忙如何在VSCode上远程调试代码,一些自己已经经历过的问题,现在已经忘记了。又在网上一顿搜索,这次记录下吧。。。 出现以下问题: 1. 终端界面总是sh-4.4 $ ÿ…...
【langchain】入门初探实战笔记(Chain, Retrieve, Memory, Agent)
1. 简介 1.1 大语言模型技术栈 大语言模型技术栈由四个主要部分组成: 数据预处理流程(data preprocessing pipeline)嵌入端点(embeddings endpoint )向量存储(vector store)LLM 终端ÿ…...
《数据结构、算法与应用C++语言描述》- 平衡搜索树 -全网唯一完整详细实现插入和删除操作的模板类
平衡搜索树 完整可编译运行代码见:Github::Data-Structures-Algorithms-and-Applications/_34Balanced search tree 概述 本章会讲AVL、红-黑树、分裂树、B-树。 平衡搜索树的应用? AVL 和红-黑树和分裂树适合内部存储的应用。 B-树适合外部存储的…...
网络路由跟踪工具
随着企业网络需求的增长,组织发现监控和管理其网络基础设施变得越来越困难。网络管理员正在转向其他工具和资源,这些工具和资源可以使他们的工作更轻松一些,尤其是在故障排除方面。 目前,网络管理员主要使用简单、免费提供的实用…...
设计模式 七大原则
1.单一职责原则 单一职责原则(SRP:Single responsibility principle)又称单一功能原则 核心:解耦和增强内聚性(高内聚,低耦合)。 描述: 类被修改的几率很大,因此应该专注…...
(1)(1.13) SiK无线电高级配置(一)
文章目录 前言 1 监控链接质量 2 诊断范围问题 3 MAVLink协议说明 前言 本文提供 SiK 遥测无线电(SiK Telemetry Radio)的高级配置信息。它面向"高级用户"和希望更好地了解无线电如何运行的用户。 !Tip 大多数用户只需要 SiK Radio v2 中提供的基本…...
drf知识--10
接口文档 # 后端把接口写好后: 登录接口:/api/v1/login ---> post---name pwd 注册接口 查询所有图书带过滤接口 # 前后端需要做对接,对接第一个东西就是这个接口文档,前端照着接口文档开发 公司3个人ÿ…...
探索 Vue 实例方法的魅力:提升 Vue 开发技能(下)
🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云…...
mysql死锁排查
查看正在进行中的事务 SELECT * FROM information_schema.INNODB_TRX;字段解释trx_id唯一事务id号,只读事务和非锁事务是不会创建id的trx_state事务的执行状态,值一般分为:RUNNING, LOCK WAIT, ROLLING BACK, and COMMITTING.trx_started事务…...
若依项目(ruoy-vue)多模块依赖情况简要分析
主pom文件关键点分析 properties标签声明变量信息:版本号、编码类型、java版本spring-boot依赖形式:spring-boot-dependencies、pom、importdependencies中添加本项目内部模块,同时在modules中声明模块packaging打包选择pom设置打包maven-co…...
【普中开发板】基于51单片机的篮球计分器液晶LCD1602显示( proteus仿真+程序+设计报告+讲解视频)
基于普中开发板51单片机的篮球计分器液晶LCD1602显示 1.主要功能:讲解视频:2.仿真3. 程序代码4. 设计报告5. 设计资料内容清单&&下载链接资料下载链接(可点击): 基于51单片机的篮球计分器液晶LCD1602显示 ( pr…...
按照层次遍历结果打印完全二叉树
按照层次遍历结果打印完全二叉树 按照推论结果: l 层首个节点位置 2h-l - 1l 层节点间距:2h-l1 - 1 编码实现 public static<E> void print(BinaryTree<E> tree) {List<List<Node<E>>> levelNodeList levelOrderTraver…...
基于SpringBoot的药店管理系统
文章目录 项目介绍主要功能截图:部分代码展示设计总结项目获取方式🍅 作者主页:超级无敌暴龙战士塔塔开 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅 项目介绍 基于SpringBoot的药店管理系统,java项目…...
Java 泛型深入解析
Java 中的泛型是一种强大的编程特性,允许我们编写更加通用和类型安全的代码。本篇博客将深入探讨 Java 泛型的各个方面,包括泛型类、泛型方法、泛型接口以及泛型通配符。 1. 泛型类 首先,让我们看一个简单的泛型类的例子。在下面的代码中&a…...
Apache Doris (六十): Doris - 物化视图
🏡 个人主页:IT贫道_大数据OLAP体系技术栈,Apache Doris,Clickhouse 技术-CSDN博客 🚩 私聊博主:加入大数据技术讨论群聊,获取更多大数据资料。 🔔 博主个人B栈地址:豹哥教你学编程的个人空间-豹哥教你学编程个人主页-哔哩哔哩视频 目录...
【javaweb】tomcat9.0中的HttpServlet
2023年12月28日,周四晚上 目录 什么是HttpServlet tomcat中的HttpServlet由谁产生 什么是HttpServlet 在Tomcat中,HttpServlet 是 Java Servlet API 中的一个抽象类,用于简化基于HTTP协议的Servlet的开发。HttpServlet 扩展了 GenericServ…...
数据结构学习笔记——查找算法中的树形查找(B树、B+树)
目录 前言一、B树(一)B树的概念(二)B树的性质(三)B树的高度(四)B树的查找(五)B树的插入(六)B树的删除 二、B树(一…...
python包chromadb安装失败总结
1,背景: 最近在学习langchain的课程,里面创建自己的知识库的Retrieval模块中,需要用到向量数据库。 所以按照官方的教程(vectorstores),准备使用chroma的向量数据库。图片来源 2,问…...
机器学习(四) -- 模型评估(2)
系列文章目录 机器学习(一) -- 概述 机器学习(二) -- 数据预处理(1-3) 机器学习(三) -- 特征工程(1-2) 机器学习(四) -- 模型评估…...
泊松分布与二项分布的可加性
泊松分布与二项分布的可加性 泊松分布的可加性 例 : 设 X , Y X,Y X,Y 相互独立 , X ∼ P ( λ 1 ) X\sim P(\lambda_1) X∼P(λ1) , Y ∼ P ( λ 2 ) Y\sim P(\lambda_2) Y∼P(λ2) , 求证 Z X Y ZXY ZXY 服从参数为 λ 1 λ 2 \lambda_1 \lambda_2 λ1λ2 …...
【PostgreSQL】约束-排他约束
【PostgreSQL】约束链接 检查 唯一 主键 外键 排他 排他约束 排他约束是一种数据库约束,用于确保某一列或多个列中的值在每一条记录中都是唯一的。这意味着任何两条记录都不能具有相同的值。 排他约束可以在数据库中创建唯一索引或唯一约束来实现。当尝试插入或更…...
Java重修第一天—学习数组
1. 认识数组 建议1.5倍速学习,并且关闭弹幕。 数组的定义:数组是一个容器,用来存储一批同种类型的数据。 下述图:是生成数字数组和字符串数组。 为什么有了变量还需要定义数组呢?为了解决在某些场景下,变…...
【C#】知识点实践序列之Lock的锁定代码块
大家好,我是全栈小5,欢迎来到《小5讲堂之知识点实践序列》文章。 2024年第1篇文章,此篇文章是C#知识点实践序列之Lock知识点,博主能力有限,理解水平有限,若有不对之处望指正! 本篇验证Lock锁定代…...
StringBad ditto (motto)
第12章 类和动态内存分配 StringBad ditto (motto): // calls StringBad (comst StringBad &) StringBad metoo - motto: // calls StringBad (const StringBad &) StringBad also StringBad (motto): // calls StringBad (const StringBad &) StringBad * pStri…...
Redis缓存击穿、缓存雪崩、缓存穿透
缓存击穿(某个热点key缓存失效) 概念 缓存中没有但数据库中有的数据,假如是热点数据,那key在缓存过期的一刻,同时有大量的请求,这些请求都会击穿到DB,造成瞬时DB请求量大、压力增大和缓存雪崩的…...
erp二次开发好还是网站开发好/合肥关键词排名优化
前言 亲爱的各位Android程序员,您们好: 我理解您们的焦虑和困惑,但我想告诉您的是:作为一名Android程序员,您依然是非常有前途和市场需求的职业人才。 首先,您要知道,移动互联网时代的普及率…...
关于免费制作网页的网站/百度域名购买
1、添加用户,首先用adduser命令添加一个普通用户,命令如下: #adduser tommy //添加一个名为tommy的用户 #passwd tommy //修改密码 Changing password for user tommy. New UNIX password: //在这里输入新密码 Retype new UNIX password: //再…...
v2ray wordpress/哪里有永久免费建站
文章目录(1)什么是等待activity出现(2)wait_activity()方法(3)获取当前页面的activity方法(4)综合练习(1)什么是等待activity出现 在启动app的时候ÿ…...
武进网站建设价格/技术教程优化搜索引擎整站
有时候数组要转为对象操作,用对象的指向操作符,有两种方法 方法一: $arr[a>10,b>100,c>Hello];$obj(Object)$arr;echo output:.$obj->c;方法二:$arr[a>10,b>100,c>Hello];$arr0 json_encode($arr);$arr1 j…...
如何建立收费视频网站/西安百度竞价托管
SQL Anywhere .NET 支持 1、ADO.NET 是 Microsoft 的 ODBC、OLE DB 和 ADO 系列中最新的数据访问 API。它是 Microsoft .NET Framework数据访问组件,可用于访问关系数据库系统。 2、SQL Anywhere .NET 数据提供程序实现了 iAnywhere.Data.SQLAnywhere 命名空间&…...
重庆疫情新闻发布会/网站seo优化分析
SQL映射 SQL映射文件 SQL映射xml文件是所有sql语句放置的地方,不同于JDBC连接的方法,需要构造方法,写statement和resultset语句才可以调用指定的sql语句,只需要把所有的sql语句写在配置文件中,根据不同的id,…...