Unity中 Xlua使用整理(二)

1.Xlua的配置应用

xLua所有的配置都支持三种方式:打标签静态列表动态列表
配置要求
列表方式均必须是static的字段/属性
列表方式均必须放到一个static类
建议不用标签方式
建议列表方式配置放Editor目录(如果是Hotfix配置,而且类位于Assembly-CSharp.dll之外的其它dll,必须放Editor目录)

1.打标签

xLua用白名单来指明生成哪些代码,而白名单通过attribute来配置,该方式方便,但在il2cpp下会增加不少的代码量,不建议使用

1.LuaCallCSharp

一个C#类型加了这个配置,xLua会生成这个类型的适配代码(包括构造该类型实例,访问其成员属性、方法,静态属性、方法)。一个类型的扩展方法(Extension Methods)加了这配置,也会生成适配代码并追加到被扩展类型的成员方法上。xLua只会生成加了该配置的类型,不会自动生成其父类的适配代码,当访问子类对象的父类方法,如果该父类加了LuaCallCSharp配置,则执行父类的适配代码。如果没有适配代码则会尝试用反射来访问,但反射访问性能不佳,在il2cpp下有可能因为代码剪裁而导致无法访问。

1.打标签

[LuaCallCSharp]
public class TestObj
{public void test(testStruct t){Debug.Log($"{t.a},{t.c}");}
}

2.静态列表

   [LuaCallCSharp]public static List<Type> luaCallCsharp = new List<Type>{typeof(TestObj),};

  上面的类加了此标签,就会生成适配代码

 2.ReflectionUse

一个C#类型类型加了这个配置,xLua会生成link.xml阻止il2cpp的代码剪裁。对于扩展方法,必须加上 LuaCallCSharp 或者 ReflectionUse 才可以被访问到。
建议所有要在Lua访问的类型,要么加LuaCallCSharp,要么加上ReflectionUse,这才能够保证在各平台都能正常运行。

如何配置?

[ReflectionUse]
public class TestReflectionUseObj
{}

link.xml保存着打上LuaCallCSharp和ReflectionUse标签的类

3.DoNotGen

指明一个类里头的部分函数、字段、属性不生成代码,通过反射访问。
只能标准 Dictionary<Type, List<string>> 的field或者property。key指明的是生效的类,value是一个列表,配置的是不生成代码的函数、字段、属性的名字。

如何配置?

[LuaCallCSharp]
public class TestDontGen
{public int a1;public int a2;
}

1.打标签(这种方式行不通)

在生成代码中,a2还是生成和a1一样的适配函数

2.静态列表

public static class ExportCfg
{[DoNotGen]public static Dictionary<Type,List<string>> dontGenDic = new Dictionary<Type, List<string>> {[typeof(TestDontGen)] = new List<string> { "a2" },};
}

4.CSharpCallLua

把一个lua函数适配到一个C# delegate(一类是C#侧各种回调:UI事件,delegate参数,比如List<T>:ForEach;另外一类场景是通过LuaTable的Get函数指明一个lua函数绑定到一个delegate),或者把一个lua table适配到一个C# interface时,使用该标签。

如何配置?

1.打标签:

   [CSharpCallLua]public interface IPlayerPosition{int x { get; set; }int y { get; set; }int z { get; set; }void add(int x, int y, int z);void sub(int x, int y, int z);}[CSharpCallLua]public delegate void AddMethod(LuaTable self, int x, int y, int z);[CSharpCallLua]public delegate Action addAc(LuaTable t, int x, int y, int z);[CSharpCallLua]public delegate void test1(int x);[CSharpCallLua]public delegate Action test2(int x);

2.静态列表:

[CSharpCallLua]
public static List<Type> CsharpCallLua = new List<Type> { typeof(IPlayerPosition),typeof(AddMethod),typeof(addAc),typeof(test1),typeof(test2),
};

 生成代码如下:接口生成独立文件,委托事件生成在DelegateGenBridge文件中

 

5.GCOptimize

xLua无参构造函数的复杂类型(struct)的默认传递方式是引用传递,当lua侧使用完毕释放该对象的引用时,会产生一次gc。
一个C#纯值类型(注:指的是一个只包含值类型的struct,可以嵌套其它只包含值类型的struct)或者C#枚举值加上这个标签之后,XLua会生成gc优化代码,在lua和c#间传递将不产生(C#)gc alloc,该类型的数组(一维?)访问也不产生gc。

如果没有配置该标签的值类型传递

public class Test{   [CSharpCallLua]public delegate Action testAction(TestGCOptimizeValue x);void Start(){luaenv = new LuaEnv();luaenv.AddLoader(customLoader);luaenv.DoString("require 'main'");ta = luaenv.Global.Get<testAction>("testAction");}private void Update(){if (Application.isPlaying){ta?.Invoke(ts);}}
}public struct TestGCOptimizeValue
{public int a;public int b;private float f;//[AdditionalProperties]public float F { get => f; set => f = value; }
}

生成的代码如下:

将struct类型装箱转换为object再进行处理。

如何配置?

[GCOptimize]
public struct TestGCOptimizeValue
{public int a;public int b;public float f;
}

 加上此标签后,就会在PackUnpack中生成适配代码

 

然后调用函数生成代码如下:

struct 满足条件如下:

1.struct允许嵌套其它struct,但它以及它嵌套的struct只能包含这几种基本类型:byte、sbyte、short、ushort、int、uint、long、ulong、float、double;例如UnityEngine定义的大多数值类型:Vector系列,Quaternion,Color。。。均满足条件,或者用户自定义的一些struct
2.该struct配置了GCOptimize属性(对于常用的UnityEngine的几个struct,Vector系列,Quaternion,Color。。。均已经配置了该属性),这个属性可以通过配置文件或者C# Attribute实现;
3.使用到该struct的地方,需要添加到生成代码列表;

6.AdditionalProperties

该标签GCOptimize的扩展配置,如果struct有的字段是私有的,需要通过属性来访问,这时就需要用到该配置(默认情况下GCOptimize只对public的field打解包)

如何配置?

如果不加此标签

[GCOptimize]
public struct TestGCOptimizeValue
{public int a;public int b;private float f;public float F { get => f; set => f = value; }
}

生成代码如下:无法生成访问f字段的代码

1.打标签方式

[GCOptimize]
public struct TestGCOptimizeValue
{public int a;public int b;private float f;[AdditionalProperties]public float F { get => f; set => f = value; }
}

 2.静态列表

  [AdditionalProperties]static Dictionary<Type, List<string>> AdditionalProperties = new Dictionary<Type, List<string>>{[typeof(TestGCOptimizeValue)] = new List<string> { "F" },};

生成代码如下:

7.BlackList

一个类型的一些成员不需要适配代码,可以通过加上该标签来实现。考虑到有可能需要把重载函数的其中一个重载列入黑名单,配置方式比较复杂,类型是 List<List<string>>,对于每个成员,在第一层List有一个条目,第二层List是个string的列表,第一个string是类型的全路径名第二个string是成员名如果成员是一个方法,还需要从第三个string开始,把其参数的类型全路径全列出来

如何配置?

[LuaCallCSharp]
public class TestBlackList
{public int a1;public int a2;public void Test(){}
}

若不加处理生成代码如下: 

1.打标签

C#代码:

[LuaCallCSharp]
public class TestBlackList
{public int a1;[BlackList]public int a2;[BlackList]public void Test(){}
}

生成代码如下: 

2.静态列表

列表中的第一个字符串是类型,第二个及以后是要屏蔽的字段

  [BlackList]public static List<List<string>> BlackList = new List<List<string>>(){new List<string>(){ "TestBlackList", "a2"},new List<string>(){ "TestBlackList", "Test"}};

生成代码:

注:
DoNotGen和ReflectionUse的区别是:1、ReflectionUse指明的是整个类;2、当第一次访问一个函数(字段、属性)时,ReflectionUse会把整个类都wrap,而DoNotGen只wrap该函数(字段、属性);
DoNotGen和BlackList的区别是:1、BlackList配了就不能用;2、BlackList能指明某重载函数,DoNotGen不能;

2.静态列表

有时我们无法直接给一个类型打标签,比如系统api,没源码的库,或者实例化的泛化类型,这时可以在一个静态类里声明一个静态字段,然后为这字段加上标签,并且这个字段需要放到一个静态类里,建议放到 Editor目录。

如何配置?

public static class ExportCfg
{[DoNotGen]public static Dictionary<Type, List<string>> dontGenDic = new Dictionary<Type, List<string>>{[typeof(TestDontGen)] = new List<string> { "a2" },};[BlackList]public static List<List<string>> BlackList = new List<List<string>>(){new List<string>(){ "TestBlackList", "a2"},new List<string>(){ "TestBlackList", "Test"}};[AdditionalProperties]public static Dictionary<Type, List<string>> AdditionalProperties = new Dictionary<Type, List<string>>{[typeof(TestGCOptimizeValue)] = new List<string> { "F" },};[LuaCallCSharp]public static List<Type> luaCallCsharp = new List<Type>{typeof(TestObj),};[CSharpCallLua]public static List<Type> CsharpCallLua = new List<Type> { typeof(IPlayerPosition),typeof(AddMethod),typeof(addAc),typeof(test1),typeof(test2),};
}

3.动态列表

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

见HotFix。

2.HotFix

1.标识要热更新的类型

1.打标签:(不建议,在高版本 Unity 不支持)

[Hotfix]
public class TestHotFix
{public void TestPrint(){Debug.Log("Before Hotfix");}
}

2.static列表:(高版本 Unity 需要把配置文件放 Editor 目录下)

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

2.API

1.xlua.hotfix(class, [method_name], fix)

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的方式。

2.base(csobj)

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

3.util.hotfix_ex(class, method_name, fix)

可以在fix函数里头执行原来的函数缺点是fix的执行会略慢。
method_name : 方法名;
fix : 用来替换C#方法的lua function

Lua侧示例:

xlua.hotfix(CS.BaseTest, 'Foo', function(self, p)print('BaseTest', p)base(self):Foo(p)
end)

3.Hotfix Flag

使用方式:

[Hotfix(HotfixFlag.xxxx)]
public class TestHotFixClass
{}
1.Stateless、Stateful

遗留设置,Stateful 方式在新版本已经删除,使用xlua.util.state代替,默认为Stateless。
这个东西不知道是个啥玩意,从utile.state的代码和Xlua例子的代码来看,就是可以为热修复类新增一些属性事件类似的东西,在构造函数中指给Lua侧的当前类(table)一个父类(metatable)。

debug.setmetatable:

 rawget,rawset:获取或设置table的值,不从原表获取或者设置

Lua 5.4 Reference Manual

使用方式:

xlua.hotfix(CS.TestHotFixClass, {  ['.ctor'] = function(self)util.state(self, {evt = {}})end;
})
2.ValueTypeBoxing

值类型的适配delegate会收敛到object(这是个啥?),好处是代码量更少,不好的是值类型会产生装箱,适用于对字段敏感的业务。

就是在生成delegate的时候,

如果是HotFix标签中包含ValueTypeBoxing,就会将方法和参数的类型转换为object类型

3.IgnoreProperty

不对属性注入及生成适配代码。

4.IgnoreNotPublic

不对非public的方法注入及生成适配代码。

5.Inline

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

6.IntKey

不生成静态字段,而是把所有注入点放到一个数组集中管理。
好处:对字段影响小。
坏处:使用不像默认方式那么方便,需要通过id来指明hotfix哪个函数,而这个id是代码注入工具时分配的,函数到id的映射会保存在 Gen/Resources/hotfix_id_map.lua.txt,并且自动加时间戳备份到 hotfix_id_map.lua.txt 同级目录,发布手机版本后请妥善保存该文件。

C#代码:

[Hotfix(HotfixFlag.IntKey)]
public class TestHotFixInkey
{public int A;public bool B; public string C;public int this[string field]{get { return 1; }set { }}public void EventCall(){Debug.Log("EventCall");}public void EventCall(int a){Debug.Log("EventCall a");}public void test(){Debug.Log("cccccccccc");}
}

生成的如下:重载函数,将会一个函数名对应多个 id

要替换掉test函数

local a = function(self)print("Lua EventCall2")
endCS.XLua.HotfixDelegateBridge.Set(4, a)local tik = CS.TestHotFixInkey()
tik:test()

结果:

 

xlua.util 提供了 auto_id_map 函数,执行一次后你就可以像以前那样直接用类,方法名去指明修补的函数。

local a = function(self)print("Lua EventCall2")
endutil.auto_id_map()
xlua.hotfix(CS.TestHotFixInkey, 'test', a)local tik = CS.TestHotFixInkey()
tik:test()

结果:

 

注意:

auto_id_map函数会require hot_id_map

一定要确保生成的hot_id_map能被加载到,如果你的自定义loader加载的文件后缀是.txt,就要确保hot_id_map.lua.txt能被加载到,如果是.lua则要确保hot_id_map.lua能被加载到。否则就会报下面的错误:

4.打补丁

Xlua可以用lua函数替换 C# 的构造函数,函数,属性,事件。

1.函数

method_name 传函数名,支持重载,不同重载都是转发到同一个 lua 函数。

见Unity中 Xlua使用整理(一)_为xlua配置搜索路径-CSDN博客中的HotFix章节

2.构造函数

构造函数对应的 method_name 是 ".ctor"。和普通函数不一样的是,构造函数的热补丁是执行原有逻辑后调用lua。

C#侧代码:

[Hotfix]
[LuaCallCSharp]
public class TestHotFixClass
{public TestHotFixClass(){Debug.Log("c# .ctor");}public TestHotFixClass(int p, int c){Debug.Log($"C# .ctor {p} , {c}");}
}

调用代码:

//调用代码:
luaenv.DoString("require 'main'");
TestHotFixClass testHotFixClass = new TestHotFixClass();
TestHotFixClass testHotFixClass1 = new TestHotFixClass(10, 20);

Lua侧代码:

xlua.hotfix(CS.TestHotFixClass, '.ctor' , function(self,p,c,d)print("Lua .ctor",p,c,d)
end)

结果:

 

3.属性

method_name 等于 get_属性名,setter 的 method_name 等于 set_属性名。

C#侧代码:

[Hotfix]
[LuaCallCSharp]
public class TestHotFixClass
{private int testProperty;public int TestProperty{ get {return testProperty;} set {testProperty = value;Debug.Log($"c# set {testProperty}");} }
}

调用代码:

  TestHotFixClass testHotFixClass = new TestHotFixClass();luaenv = new LuaEnv();luaenv.AddLoader(customLoader);testHotFixClass.TestProperty = 10;Debug.Log($"before get {testHotFixClass.TestProperty}");luaenv.DoString("require 'main'");Debug.Log($"after get {testHotFixClass.TestProperty}");testHotFixClass.TestProperty = 100;Debug.Log($"set after get {testHotFixClass.TestProperty}");

Lua侧代码:

xlua.hotfix(CS.TestHotFixClass, {  set_TestProperty = function(self, v)self.testProperty = vprint('Lua set_TestProperty', v)end;get_TestProperty = function(self)print('Lua get_TestProperty')return self.testPropertyend
})

结果:

 

4.[]操作符

赋值对应 set_Item,取值对应 get_Item。第一个参数是 self,赋值后面跟 key,value,取值只有 key 参数,返回值是取出的值。

C#侧代码:

 public int this[string field]{get{ return 1;}set{}}public string this[int index]{get{ return "aaabbbb";}set{}}

C#侧调用代码:

 Debug.Log(testHotFixClass[1]);Debug.Log(testHotFixClass["cc"]);luaenv.DoString("require 'main'");Debug.Log(testHotFixClass[1]);Debug.Log(testHotFixClass["cc"]);

Lua侧代码:

xlua.hotfix(CS.TestHotFixClass, {  get_Item = function(self, k)print('get_Item', k)return 1024end;set_Item = function(self, k, v)print('set_Item', k, v)end;
})

结果:

5.其他操作符

使用C#的内部操作符可以覆盖对应函数,比如+号的操作符函数名是 op_Addition,

操作符还有哪些可以看下边这篇文章

C#中如何利用操作符重载和转换操作符 (转载) - PowerCoder - 博客园 (cnblogs.com)

C#代码:

[Hotfix]
[LuaCallCSharp]
public class HotFixOtherOperator
{public static int operator +(HotFixOtherOperator a, HotFixOtherOperator b){Debug.Log("C# op_add");return 0;}
}

调用代码:

  HotFixOtherOperator ho1 = new HotFixOtherOperator();HotFixOtherOperator ho2 = new HotFixOtherOperator();int a = ho1 + ho2;luaenv.DoString("require 'main'");

Lua代码:

xlua.hotfix(CS.HotFixOtherOperator,"op_Addition",function(a,b)print("Lua Op_add")return 0end)local ho1 = CS.HotFixOtherOperator()
local ho2 = CS.HotFixOtherOperator()
local a = ho1 + ho2

结果:

 

6.事件

+= 操作符是 add_事件名-=对应的是 remove_事件名。这两个函数均是第一个参数是self,第二个参数是操作符后面跟的delegate。
C#代码:

[Hotfix]
[LuaCallCSharp]
public class TestHotFixClass
{public event Action myEvent;
}

调用代码:

    luaenv.DoString("require 'main'");TestHotFixClass testHotFixClass = new TestHotFixClass();testHotFixClass.myEvent += TestHotfixEvent;testHotFixClass.myEvent -= TestHotfixEvent;

Lua代码:

-- 事件
xlua.hotfix(CS.TestHotFixClass, {  ['.ctor'] = function(self)util.state(self, {evt = {}})end;add_myEvent = function(self, cb)print('add_Event', cb)table.insert(self.evt, cb)end;remove_myEvent = function(self, cb)print('remove_Event', cb)for i, v in ipairs(self.evt) doif v == cb thentable.remove(self.evt, i)breakendendend;
})

结果:

通过 xlua.private_accessible(版本号大于2.1.11不需要调用 xlua.private_accessible)来直接访问,事件对应的私有 delegate 的直接访问后,可以通过对象的"&事件名"字段直接触发事件,例如 self['&MyEvent'](),其中MyEvent是事件名。

7.析构函数

method_name 是 "Finalize",传一个 self 参数。析构函数的热补丁并不是替换,而是开头调用 lua 函数后继续原有逻辑。

C#侧代码:

[Hotfix]
[LuaCallCSharp]
public class TestHotFixClass
{~TestHotFixClass(){Debug.Log("执行析构函数");}
}

调用代码:

     TestHotFixClass testHotFixClass = new TestHotFixClass();luaenv = new LuaEnv();luaenv.AddLoader(customLoader);System.GC.Collect();System.GC.WaitForPendingFinalizers();luaenv.DoString("require 'main'");TestHotFixClass testHotFixClass1 = new TestHotFixClass();luaenv.FullGc();System.GC.Collect();System.GC.WaitForPendingFinalizers();

Lua侧代码:

xlua.hotfix(CS.TestHotFixClass,"Finalize", function(self)print('Finalize', self)
end)

结果:

注:System.GC.Collect()

 System.GC.WaitForPendingFinalizers

luaenv.FullGC():清理GC

8.泛型

其他规则一致,每个泛化类型实例化后都是一个独立的类型,只能针对实例化后的类型分别打补丁。

C#代码:

[Hotfix]
public class TestGeneric<T>
{public TestGeneric(){Debug.Log($"aaaaa,{typeof(T)}");}
}

调用代码:

TestGeneric<int> testGeneric = new TestGeneric<int>();
TestGeneric<float> testGeneric1 = new TestGeneric<float>();
luaenv.DoString("require 'main'");
TestGeneric<int> testGeneric2 = new TestGeneric<int>();
TestGeneric<float> testGeneric3 = new TestGeneric<float>();

Lua代码:

xlua.hotfix(CS.TestGeneric(CS.System.Int32),".ctor", function(self)print("LUA INT32")
end)xlua.hotfix(CS.TestGeneric(CS.System.Single),".ctor", function(self)print("LUA FLAOTG4")
end)

结果:

如果Lua侧没有泛型的单独函数不会报错,只会执行C#侧的泛型函数

TestGeneric<double> testGeneric2 = new TestGeneric<double>();

 

9.Unity协程

通过 util.cs_generator 可以用一个 function 模拟一个 IEnumerator,yield return使用在里头的 coroutine.yield模拟。

C#代码:

[Hotfix]
public class HotFixSubClass : MonoBehaviour
{IEnumerator Start(){while (true){yield return new WaitForSeconds(3);Debug.Log("C# Wait for 3 seconds");}}
}

调用代码:

 Unity协程的使用请看3.1节。

C#代码:

[Hotfix]
public class HotFixCoroutine: MonoBehaviour
{private void Start(){StartCoroutine(CoroutineStart());}IEnumerator CoroutineStart(){while (true){yield return new WaitForSeconds(1);Debug.Log("c# Wait for 3 seconds");}}
}

调用代码:

new GameObject().AddComponent<HotFixCoroutine>();
luaenv.DoString("require 'main'");
new GameObject().AddComponent<HotFixCoroutine>();

Lua代码:

xlua.hotfix(CS.HotFixCoroutine,{CoroutineStart = function(self)return util.cs_generator(function()while true docoroutine.yield(CS.UnityEngine.WaitForSeconds(3))print('Wait for 3 seconds')endend)end;
})

 结果:

10.整个类

如果要替换整个类,使用一个 table,按 method_name = function 组织即可。

注:将打补丁1-9小节挑选合适的填入table({})中

xlua.hotfix(CS.类名, {  --放入要热修复的代码
})

3.其他

 1.Unity协程的使用

C#代码:

新建一个MonoBehaviour,

   public class TestCoroutine : MonoBehaviour{}

添加WaitForSeconds到LuaCallCSshrap的静态列表中,供Lua侧调用

Lua代码:

local gameobject = CS.UnityEngine.GameObject('CoroutineTest')
CS.UnityEngine.Object.DontDestroyOnLoad(gameobject)
local cs_coroutine_runner = gameobject:AddComponent(typeof(CS.TestCoroutine))local times = 5
cs_coroutine_runner:StartCoroutine(util.cs_generator(function()while (times > 0) doprint('coroutine aaaaa')coroutine.yield(CS.UnityEngine.WaitForSeconds(1))times = times - 1end
end))

结果:

 

参考链接:

介绍 — XLua (tencent.github.io)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/505900.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Flink三种集群部署模型

这里写自定义目录标题 Flink 集群剖析Flink 应用程序执行Flink Session 集群&#xff08;Session Mode&#xff09;Flink Job 集群&#xff08;以前称为per-job&#xff09;Flink Application 集群&#xff08;Application Mode&#xff09; 参考 Flink 集群剖析 Flink 运行时…

Windows10环境下安装RabbitMq折腾记

最近有个老项目需要迁移到windows10环境&#xff0c;用的是比较老的rabbitmq安装包&#xff0c;如下所示。经过一番折腾&#xff0c;死活服务起不来&#xff0c;最终果断放弃老版本启用新版本。现在把折腾过程记录下&#xff1a; 一、安装erlang 安装完成后的目录结构&#xff…

【深度学习】通俗理解偏差(Bias)与方差(Variance)

在统计学习中&#xff0c;我们通常使用方差与偏差来衡量一个模型 1. 方差与偏差的概念 偏差(Bais)&#xff1a; 预测值和真实值之间的误差 方差(Variance)&#xff1a; 预测值之间的离散程度 低偏差低方差、高偏差低方差&#xff1a; 图中每个点表示同一个模型每次采样出不同…

(五)ROS通信编程——参数服务器

前言 参数服务器在ROS中主要用于实现不同节点之间的数据共享&#xff08;P2P&#xff09;。参数服务器相当于是独立于所有节点的一个公共容器&#xff0c;可以将数据存储在该容器中&#xff0c;被不同的节点调用&#xff0c;当然不同的节点也可以往其中存储数据&#xff0c;关…

使用Keil创建FreeRTOS工程

之前记录了使用Keil创建Keil自带的RTX5的RTOS和使用CubeMX创建FreeRTOS。这次来记录下使用Keil创建FreeRTOS。使用CMSIS-RTOS2将FreeRTOS封装好 1.Pack增加CMSIS-FreeRTOS 2.CMSIS配置为FreeRTOS 点击Resolve后再点击OK即可 3.屏蔽相关文件 4.屏蔽3个中断 将void PendSV_Han…

LLM - Llama 3 的 Pre/Post Training 阶段 Loss 以及 logits 和 logps 概念

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/145056912 Llama 3 是 Meta 公司发布的开源大型语言模型&#xff0c;包括具有 80 亿和 700 亿参数的预训练和指令微调的语言模型&#xff0c;支持…

Unity + Firebase + GoogleSignIn 导入问题

我目前使用 Unity版本&#xff1a;2021.3.33f1 JDK版本为&#xff1a;1.8 Gradle 版本为&#xff1a;6.1.1 Firebase 版本: 9.6.0 Google Sign In 版本为&#xff1a; 1.0.1 问题1 &#xff1a;手机点击登录报错 apk转化成zip&#xff0c;解压&#xff0c;看到/lib/armeabi-v…

安卓投屏电脑最详细教程

安卓手机投屏到电脑的操作可以通过多种方式实现&#xff0c;最常见的方法有使用 Scrcpy、911投屏 或者 Windows 10/11 自带的投屏功能。下面是几个常用方法的详细教程&#xff1a; 方法 1&#xff1a;使用 Scrcpy &#xff08;推荐&#xff0c;免费的开源工具&#xff09; Sc…

VSCode配置php开发环境

我偷偷地告诉你&#xff0c; 有一个地方叫做稻城&#xff0c;我要和我最心爱的人一起去到那里... 2025.1.10 声明 仅作为个人学习使用&#xff0c;仅供参考 不知道如何配置php本地环境的&#xff0c;请翻阅 笔者的上一篇文章 正文 VSCode安装 官网&#xff1a;Download Vis…

StarRocks Awards 2024 年度贡献人物

在过去一年&#xff0c;StarRocks 在 Lakehouse 与 AI 等关键领域取得了显著进步&#xff0c;其卓越的产品功能极大地简化和提升了数据分析的效率&#xff0c;使得"One Data&#xff0c;All Analytics" 的愿景变得更加触手可及。 虽然实现这一目标的道路充满挑战且漫…

python学习笔记—17—数据容器之字符串

1. 字符串 (1) 字符串能通过下标索引来获取其中的元素 (2) 旧字符串无法修改特定下标的元素 (3) index——查找字符串中任意元素在整个字符串中的起始位置(单个字符或字符串都可以) tmp_str "supercarrydoinb" tmp_position1 tmp_str.index("s") tmp_p…

跟着逻辑先生学习FPGA-第八课 基于 I2C 协议的 EEPROM 驱动控制

硬件平台&#xff1a;征战Pro开发板 软件平台&#xff1a;Vivado2018.3 仿真软件&#xff1a;Modelsim10.6d 文本编译器&#xff1a;Notepad 征战Pro开发板资料 链接:https://pan.baidu.com/s/1AIcnaGBpNLgFT8GG1yC-cA?pwdx3u8 提取码:x3u8 1知识背景 I2C 通讯协议&#xf…

Mac上鸿蒙配置HDC报错:zsh: command not found: hdc -v

这个问题困扰了好久&#xff0c;按照官方文档去配置的&#xff0c;就是会一直报错&#xff0c;没有配置成功&#xff0c;主要原因是官网ide的路径可能和你本地的ide的路径不一致&#xff0c;因为官网的ide版本可能是最新的 一.先查找你本地的toolchains目录在哪里&#xff0c;…

基于华为ENSP的OSPF状态机、工作过程、配置保姆级别详解(2)

本篇技术博文摘要 &#x1f31f; 基于华为enspOSPF状态机、OSPF工作过程、.OSPF基本配置等保姆级别具体详解步骤&#xff1b;精典图示举例说明、注意点及常见报错问题所对应的解决方法 引言 &#x1f4d8; 在这个快速发展的技术时代&#xff0c;与时俱进是每个IT人的必修课。我…

【Rust自学】11.1. 编写和运行测试

喜欢的话别忘了点赞、收藏加关注哦&#xff0c;对接下来的教程有兴趣的可以关注专栏。谢谢喵&#xff01;(&#xff65;ω&#xff65;) 11.1.1. 什么是测试 在Rust里一个测试就是一个函数&#xff0c;它被用于验证非测试代码的功能是否和预期一致。 在一个测试的函数体里通…

计算机网络 (31)运输层协议概念

一、概述 从通信和信息处理的角度看&#xff0c;运输层向它上面的应用层提供通信服务&#xff0c;它属于面向通信部分的最高层&#xff0c;同时也是用户功能中的最低层。运输层的一个核心功能是提供从源端主机到目的端主机的可靠的、与实际使用的网络无关的信息传输。它向高层用…

cache原理

理论基础 时间局部性空间局部性 存储结构 存储器 ROMRAM SRAM->CACHEDRAM->MEM CACHE与主存映射 直接映射 假定主存储器32位地址&#xff0c;cache行64B&#xff0c;cache容量512B&#xff0c;则cache有8行 全相联映射 假定主存储器32位地址&#xff0c;cache…

嵌入式入门Day38

C Day1 第一个C程序C中的输入输出输出操作coutcin练习 命名空间使用方法自定义命名空间冲突问题 C对字符串的扩充C风格字符串的使用定义以及初始化C风格字符串与C风格字符串的转换C风格的字符串的关系运算常用的成员变量输入方法 布尔类型C对堆区空间使用的扩充作业 第一个C程序…

流浪猫流浪狗领养PHP网站源码

源码介绍 流浪猫流浪狗领养PHP网站源码&#xff0c;适合做猫狗宠物类的发信息发布。当然其他信息发布也是可以的。 导入数据库&#xff0c;修改数据库配置/application/database.php 设置TP伪静态&#xff0c;设置运行目录&#xff0c; 后台&#xff1a;/abcd.php/dashboard?…

深度学习|表示学习|一个神经元可以干什么|02

如是我闻&#xff1a; 如果我们只有一个神经元&#xff08;即一个单一的线性或非线性函数&#xff09;&#xff0c;仍然可以完成一些简单的任务。以下是一个神经元可以实现的功能和应用&#xff1a; 1. 实现简单的线性分类 输入&#xff1a;一组特征向量 x x x 输出&#xff…