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

【unity c#】深入理解string,以及不同方式构造类与反射的性能测试(基于BenchmarkDotNet)

出这篇文章的主要一个原因就是ai回答的性能差异和实际测试完全不同,比如说是先获取构造函数再构造比Activator.CreateInstance(type)快,实际却相反
对测试结果的评价基于5.0,因为找不到unity6确切使用的net版本,根据c#9推测是net5.0

起因:看到animancer对string的描述,我开始纠结起来要不要使用,于是有此文章
省流版就是
因为字符串常量池,字面量和方法参数都是直接比较引用,而且无论"string"+"string"还是两个相同长度不同内容的字符串都是比较的引用,如果引用不同,会比较长度,只有在使用变量存字符串,并且运行时动态修改,导致引用不同

  1. 只要不使用变量存字符串,并且运行时动态修改,就可以放心用string
  2. 反射用委托
  3. 构造用表达式树或者Activator.CreateInstance(反正不会经常调用)
  4. 拼接字符串用StringBuilder
  5. 有时间纠结性能不如多做两个玩法
    stringbuilder和字符串常量池都是学java时的遗产,但学c#好像没被提到过,所以在这里提一嘴
    在这里插入图片描述StringReference 本质是 通过字典缓存引用比较,也就是说,如果通过动态字符串获取缓存,仍然会在取值时执行一次字符比较判断键是否相等。如果BenchmarkDotNet是可信的,那么StringReference可能 并没有起到提高效率的效果。反而因为隐式转换额外多消耗了一点

补充:

所以最终我决定放弃包装string,如果有需要扩展的就直接用【扩展方法】就好了
不过通过隐式类型转换+字典的缓存方式也让人大开眼界,留个印象说不定哪天用得上

BenchmarkDotNet可参:https://blog.csdn.net/x740073529/article/details/119934597
安装可参:https://www.cnblogs.com/WilsonPan/p/12904664.html
视频可参:https://www.bilibili.com/video/BV1DM411T7rb
简单来说就是安装包,在main入口执行,记得将运行设置为运行模式而不是调试模式:
在这里插入图片描述

为了8和5兼容需要删除自动生成全局using的设置:ImplicitUsings。右键,编辑项目文件可以找到

<PropertyGroup><OutputType>Exe</OutputType><TargetFrameworks>net8.0;net5.0</TargetFrameworks><Nullable>enable</Nullable>
</PropertyGroup>

String

主要还是参考作用,真正真实的结果只能到unity实际测试了

结论

  • 前置知识:直接用字面量(= ‘abc’)是得到字符串常量池中的引用,所以相同字面量的字符串引用地址相等。而new或者拼接动态字符串才会开辟新的内存空间
  • 常量形式的string哪怕是"string"+"string"的形式,也是被字符串常量池优化过的,相当于直接比较引用
  • 字符串的等号应该是被重写的,调用equals,并且优先比较引用,也就时候说,只有在使用变量存字符串,并且运行时动态修改,并且长度不同,才会低效
  1. 查找字符串为键的字典:取hash比较,快
  2. 查找字符串为键的字典,取值时动态拼接字符串多出的时间消耗约等于变量拼接常量再比较,意味着除了hash计算还有一次字符比较的操作
  3. 查找值类型为键的字典:遥遥领先
  4. 引用类型作为键:比字符串稍快
  5. 包装字符串为类的效果:比引用类型稍慢
  6. 动态拼接字符串来查找: 不缓存则较慢
  7. 常量字符串比较:比引用比较更快,可能有优化吧
  8. 不同常量不同长度字符串比较:稍慢,应该是判断了字符串长度
  9. 拼接常量字符串:和常量比较一样,看来是自动优化了
  10. 变量拼接常量再比较(normal3):很慢。这里应该是比较的字符
  11. 不同常量比较:快

这里是总览,命名不规范,建议和代码对照看
在这里插入图片描述

源码

在 .NET 5 之前,很多基础类型(例如 string)的实现是在 C++ 编写的
所以只能看net8的来参考了

 public override bool Equals([NotNullWhen(true)] object? obj){if (ReferenceEquals(this, obj))return true;if (!(obj is string str))return false;if (this.Length != str.Length)return false;return EqualsHelper(this, str);}private static bool EqualsHelper(string strA, string strB)
{Debug.Assert(strA != null);Debug.Assert(strB != null);Debug.Assert(strA.Length == strB.Length);return SpanHelpers.SequenceEqual(ref Unsafe.As<char, byte>(ref strA.GetRawStringData()),ref Unsafe.As<char, byte>(ref strB.GetRawStringData()),((uint)strA.Length) * sizeof(char));
}
补充
  1. 不同常量相同长度字符串:引用级
  2. 每个字符比较:比动态拼接快。推测是少了一系列引用比较的缘故
  3. 比较常量的hash:不如每个字符比较一遍
  4. Equals比较不同常量:比引用慢,比hash快,比较的是字符?
  5. Equals比较相同常量:五代比等号慢,说明等号有特殊处理
    在这里插入图片描述
    可以看到5代的Equals被8代薄纱,可能是把等号的判断移到Equals了
    在这里插入图片描述
    看其他博客说 动态拼接的比较方式为比较两个字符串的第一个字符:相等则比较第二个,实际测试并不是,比较字符串时改变差异字符的位置没有影响性能,估计是
[Benchmark]
public void xiangdengNormal7()
{for (int i = 0; i < N; i++){var t = "asdasdfasdfasdfsafasdf" == "asdasdfasdfasdfsafasdp";}
}
[Benchmark]
public void xiangdengNormal8()
{string a = "asdasdfasdfasdfsafasdf";string b = "asdasdfasdfasdfsafasdf";for (int i = 0; i < N; i++){for (int j = 0; j < a.Length; j++){var t = a[j] == b[j];}}
}
[Benchmark]
public void xiangdengNormal9()
{ for (int i = 0; i < N; i++){var t = "asdasdfasdfasdfsafasdf".GetHashCode() == "asdasdfasdfasdfsafasdp".GetHashCode();}
}
[Benchmark]
public void xiangdengNormal10()
{for (int i = 0; i < N; i++){var t = "asdasdfasdfasdfsafasdf".Equals("asdasdfasdfasdfsafasdp");}
}
[Benchmark]
public void xiangdengNormal12()
{for (int i = 0; i < N; i++){var t = "asdasdfasdfasdfsafasdf".Equals("asdasdfasdfasdfsafasdf");}
}
不用循环
  • 这里是没用循环的结果,缓存每用上导致结果不准确,所以用hash的结果偏慢。但也反映出hash和string常量引用不同,反而丢失了常量池的优化
  • 可以看到net8 比较动态字符串也快了三四倍
  • 其他:模板字符串消耗更高
    在这里插入图片描述

测试getHashCode的消耗

可以看出来字典查找的损耗就是源自于此,而且每次都是重新获取hash

[Benchmark]
public void getHash1()
{"asdasdfasdfasdfsafasdf".GetHashCode();
}
[Benchmark]
public void getHash2()
{stringHash.GetHashCode();
}

在这里插入图片描述

测试代码

[SimpleJob(BenchmarkDotNet.Jobs.RuntimeMoniker.Net50)]   // 在Net5.0测试(unity6 => c#9 推测=> net5.0)
[SimpleJob(BenchmarkDotNet.Jobs.RuntimeMoniker.Net80)]
public class StringTest
{// 测试数据量private const int N = 100;// 测试用的字符串和 StringHash 字典private Dictionary<string, string> stringDict;private Dictionary<int, int> intDict;private Dictionary<YourClass, int> objDict;private YourClass obj = new YourClass();private Dictionary<StringHash, StringHash> stringHashDict;private StringHash stringHash = "asdasdfasdfasdfsafasdf";// 引用应该是相同的  用字典缓存了的private StringHash stringHash2 = "asdasdfasdfasdfsafasdf";private string key = "Value";// 初始化测试数据[GlobalSetup]public void Setup(){key += "10";stringDict = new Dictionary<string, string>(N);stringHashDict = new Dictionary<StringHash, StringHash>(N);intDict = new Dictionary<int, int>(N);objDict = new Dictionary<YourClass, int>(N);// 插入数据objDict.Add(obj, 1); // 对象字典for (int i = 0; i < N; i++){string value = $"Value{i}";stringDict.Add(value, value); // 字符串字典stringHashDict.Add(value, value); // StringHash 字典intDict.Add(i, i); // 整数字典}}// 字符串字典插入性能//[Benchmark]//public void StringDictInsertion()//{//    for (int i = 0; i < N; i++)//    {//        string value = $"Value{i}";//        stringDict[value] = value;//    }//} StringHash 字典插入性能//[Benchmark]//public void StringHashDictInsertion()//{//    for (int i = 0; i < N; i++)//    {//        //string value = $"Value{i}";//        stringHashDict[new StringHash(value)] = new StringHash(value);//    }//}// 字符串字典查找性能[Benchmark]public void StringDictLookup(){for (int i = 0; i < N; i++){string value = "Value" + i;stringDict.TryGetValue(value, out _);}}[Benchmark]public void StringDictLookup2(){for (int i = 0; i < N; i++){string value = "Value10";stringDict.TryGetValue(value, out _);}}[Benchmark]public void IntDictLookup(){for (int i = 0; i < N; i++){intDict.TryGetValue(10, out _);}}[Benchmark]public void ObjDictLookup(){for (int i = 0; i < N; i++){objDict.TryGetValue(obj, out _);}} 动态字符串字典查找性能[Benchmark]public void StringDictLookupByDynamic(){for (int i = 0; i < N; i++){string value = "Value";stringDict.TryGetValue(value + "10", out _);}}[Benchmark]public void StringDictLookupByDynamic2(){for (int i = 0; i < N; i++){ stringDict.TryGetValue(key, out _);}}// StringHash 字典查找性能[Benchmark]public void StringHashDictLookup(){for (int i = 0; i < N; i++){//string value = $"Value{i}";stringHashDict.TryGetValue(new StringHash("Value10"), out _);}}[Benchmark]public void StringHashDictLookup2(){for (int i = 0; i < N; i++){//这里是缓存的stringHashDict.TryGetValue("Value10", out _);}}[Benchmark]public void xiangdengNormal(){for (int i = 0; i < N; i++){var t = "asdasdfasdfasdfsafasdf" == "asdasdfasdfasdfsafasdf";}}[Benchmark]public void xiangdengNormal2(){for (int i = 0; i < N; i++){var t = "asdasdfasdfasdfsafasdf" == "asdasdfasdfasdf" + "safasdf";}}[Benchmark]public void xiangdengNormal3(){for (int i = 0; i < N; i++){string a = "asdasdfasdfasdf";var t = "asdasdfasdfasdfsafasdf" == a + "safasdf";}}[Benchmark]public void xiangdengNormal4(){for (int i = 0; i < N; i++){var t = "asdasdfasdfasdfsafasdf" == "asdasdfasdfasdfsafasdfasfaa";}}[Benchmark]public void xiangdengNormal5(){for (int i = 0; i < N; i++){string a = "asdasdfasdfasdfsafasdf";string b = "asdasdfasdfasdfsafasdfasfaa";var t = a == b;}}[Benchmark]public void xiangdengHash(){for (int i = 0; i < N; i++){var t = stringHash == "asdasdfasdfasdfsafasdf";}}[Benchmark]public void xiangdengHash2(){for (int i = 0; i < N; i++){var t = stringHash == "asdasdfasdfasdfsafasdfasfaa";}}[Benchmark]public void xiangdengRefrence(){var t = stringHash == stringHash2;}[Benchmark]public void xiangdengInt(){var t = 123 == 123;}
}[Serializable]
public class StringHash : IComparable<StringHash>
{// 字段 private readonly string name;public int hash;private static readonly Dictionary<string, StringHash> StringHashDic = new(256);/// <summary>/// 获取或添加/// </summary>/// <param name="value"></param>/// <returns></returns>public static StringHash Get(string value){if (value is null) return null;if (!StringHashDic.TryGetValue(value, out var reference))StringHashDic.Add(value, reference = new(value));return reference;}// 构造函数public StringHash(string name){this.name = name;hash = HashCode.Combine(name);// 对于相同字符串,生成相同hash码// hash =  Animator.StringToHash(name);}// 重写隐式转换// 在 string 类型和自定义的 StateHashName 类型之间进行自动转换  就可以直接=[MethodImpl(MethodImplOptions.AggressiveInlining)]public static implicit operator StringHash(string value) => Get(value);public static implicit operator string(StringHash value) => value?.name;// 覆盖 ToString 方法// 特性:尽可能将方法内联化   比委托调用快十倍[MethodImpl(MethodImplOptions.AggressiveInlining)]public override string ToString() => name;// 重载 == 运算符public static bool operator ==(StringHash left, StringHash right){if (ReferenceEquals(left, null))return ReferenceEquals(right, null);return left.Equals(right);}// 重载 != 运算符public static bool operator !=(StringHash left, StringHash right){return !(left == right);}// 重写 Equals 和 GetHashCode 方法  //public override bool Equals(object obj)//{//    if (ReferenceEquals(this, obj)) return true;//    if (obj is StringHash other)//    {//        // 检查哈希值//        if (hash != other.hash)//            return false;//        return true;//        // 哈希值相等时,进一步比较字符串内容 处理hash碰撞//        //return name == other.name;// == 对于 null 会非常安全,但 Equals 可能会抛出异常//    }//    return false;//}// 会被字典调用// 如果键冲突,会调用Equals public override int GetHashCode(){return hash;}// 比较方法public int CompareTo(StringHash other) => name.CompareTo(other?.name);
}

构造类测试

反射经常能简化代码,但也有性能损耗,索性可以避免,委托只是其中一种方式。

  1. 带缓存表达式树调用构造函数(委托) : 只比正常慢了一点
  2. 表达式树(委托)
  3. 正常构造
  4. 通过反射获取构造方法再调用:慢了十倍以上
  5. 反射+强制类型转换:慢了5倍的样子
  6. 反射+as 类型转换:as确实比强转慢一点,但不多
  7. 泛型反射:和反射一样
    结果: net8.0对反射似乎有不小的优化,可惜unity版本更不上
    在这里插入图片描述
    测试代码
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using System.Linq.Expressions;
using System;  [MemoryDiagnoser]
[SimpleJob(BenchmarkDotNet.Jobs.RuntimeMoniker.Net50)]   // 在Net5.0测试(unity6 => c#9 推测=> net5.0)
[SimpleJob(BenchmarkDotNet.Jobs.RuntimeMoniker.Net80)]
public class TestClass
{private Action _delegate;private event Action _event;int iterations = 10000;static void Main(string[] args)//main函数{// 运行 BenchmarkTest 里标记为 Benchmark 的方法,比较它们的性能var summary = BenchmarkRunner.Run<TestClass>();Console.WriteLine(summary);} private Func<YourClass> constructorDelegate;[GlobalSetup]public void Setup(){var type = typeof(YourClass);// 获取无参数的构造函数var constructor = type.GetConstructor(Type.EmptyTypes);// 创建一个表达式树,表示调用构造函数的操作var newExpression = Expression.New(constructor);// 创建一个 Lambda 表达式,指定返回类型为 YourClassvar lambda = Expression.Lambda<Func<YourClass>>(newExpression);// 编译表达式树,得到一个委托constructorDelegate = lambda.Compile();}[Benchmark]public void biaodashiHuancun(){YourClass obj = constructorDelegate();}[Benchmark]public void biaodashi(){var type = typeof(YourClass);// 获取无参数的构造函数var constructor = type.GetConstructor(Type.EmptyTypes);// 创建一个表达式树,表示调用构造函数的操作var newExpression = Expression.New(constructor);// 创建一个 Lambda 表达式,指定返回类型为 YourClassvar lambda = Expression.Lambda<Func<YourClass>>(newExpression);// 编译表达式树,得到一个委托var constructorDelegate = lambda.Compile();YourClass obj = constructorDelegate();} [Benchmark]public void Normal(){YourClass obj = new YourClass();}[Benchmark]public void gouzao(){var type = typeof(YourClass);var constructor = type.GetConstructor(Type.EmptyTypes); YourClass obj = constructor.Invoke(null) as YourClass;}[Benchmark]public void fanshe(){var type = typeof(YourClass); // 请替换为你的类 YourClass? obj = (YourClass)Activator.CreateInstance(type);}[Benchmark]public void fansheAs(){var type = typeof(YourClass); // 请替换为你的类 YourClass? obj = Activator.CreateInstance(type) as YourClass;}[Benchmark]public void fansheFanxing(){var type = typeof(YourClass);YourClass? obj = Activator.CreateInstance<YourClass>();}}//省略了字段
public class YourClass
{ public YourClass(){ }
}

额外测试

空类测试

  1. 类的属性是否影响构造消耗:是
  2. as的消耗具体多大:可以忽略,甚至更快了
    在这里插入图片描述

十几个字段的类

  1. as转换为接口和as转换为类消耗差距: 差不多
  2. as和is消耗:差不多
    在这里插入图片描述在这里插入图片描述

代码:

[Benchmark]
public void fanshe()
{var type = typeof(YourClass); // 请替换为你的类 object obj = Activator.CreateInstance(type);
}
[Benchmark]
public void fansheAs()
{var type = typeof(YourClass); // 请替换为你的类 YourClass? obj = Activator.CreateInstance(type) as YourClass;
}
[Benchmark]
public void fansheAsInterface()
{var type = typeof(YourClass); // 请替换为你的类 IYourInterface? obj = Activator.CreateInstance(type) as IYourInterface;
}
[Benchmark]
public void TestIS()
{var type = typeof(YourClass); // 请替换为你的类 _ = Activator.CreateInstance(type) is IYourInterface;
}

反射测试

参考:https://blog.walterlv.com/post/create-delegate-to-improve-reflection-performance.html

  1. 直接调用
  2. 通过方法(委托)调用:慢了十倍 (可能是有额外的检查)
  3. 通过委托调用:和通过方法差不多
  4. 通过缓存的反射方法:慢了百倍
  5. 通过反射:慢了两百倍
    在这里插入图片描述
代码
public class Fanshe
{private StubClass instance;private MethodInfo method;private Func<int, int> pureFunc;private Func<int, int> func;// 初始化测试数据[GlobalSetup]public void Setup(){instance = new StubClass();method = typeof(StubClass).GetMethod(nameof(StubClass.Test), new[] { typeof(int) });pureFunc = value => value;// 使用反射创建一个委托func = InstanceMethodBuilder<int, int>.CreateInstanceMethod(instance, method);}// 直接调用[Benchmark]public void DirectCall(){var result = instance.Test(5);}// 使用 Func 委托调用[Benchmark]public void FuncCall(){var result = pureFunc(5);}// 使用反射创建的委托调用[Benchmark]public void DelegateFromReflection(){var result = func(5);}// 使用缓存的反射方法调用[Benchmark]public void CachedReflectionCall(){var result = method.Invoke(instance, new object[] { 5 });}// 使用每次都反射查找的方法调用[Benchmark]public void DirectReflectionCall(){var result = typeof(StubClass).GetMethod(nameof(StubClass.Test), new[] { typeof(int) })?.Invoke(instance, new object[] { 5 });}
}

相关文章:

【unity c#】深入理解string,以及不同方式构造类与反射的性能测试(基于BenchmarkDotNet)

出这篇文章的主要一个原因就是ai回答的性能差异和实际测试完全不同&#xff0c;比如说是先获取构造函数再构造比Activator.CreateInstance(type)快&#xff0c;实际却相反 对测试结果的评价基于5.0&#xff0c;因为找不到unity6确切使用的net版本&#xff0c;根据c#9推测是net5…...

防抖和节流的方法详解和CSS文本溢出小知识

1.防抖 防抖:在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时 场景:搜索框输入发请求,一些拖拽盒子,或者滚动事件 防抖的实现:利用间歇函数 const timer =setTimeout(callback函数,间隔时间) //执行完会返回自身的这个定时器的编号//事件所触发的函…...

深度解析:Maven 和 Gradle 的使用比较及常见仓库推荐

Maven 和 Gradle 是 Java 项目中最常用的构建工具。它们各有优势&#xff0c;适用于不同的场景。本文将对两者进行详细的对比&#xff0c;并推荐一些常用的 Maven 和 Gradle 仓库&#xff0c;帮助开发者高效管理依赖。 一、Maven 和 Gradle 的使用比较 1.1 基本介绍 Maven 基…...

CSS---实现盒元素div内input/textarea的focus状态时给父元素加属性!

注意兼容性&#xff0c;低版本浏览器无效 要实现当 textarea 文本框获得焦点时&#xff0c;自动给其父元素添加类名或样式&#xff0c;您可以使用 CSS 的 :focus-within 伪类选择器。这个选择器会在元素本身或其任何子元素获得焦点时应用样式。 示例代码 假设您有以下 HTML 结…...

施耐德变频器ATV320系列技术优势:创新与安全并重

在工业自动化领域&#xff0c;追求高效、安全与智能已成为不可阻挡的趋势。施耐德变频器ATV320系列凭借其强大的设计标准和全球认证&#xff0c;成为能够帮助企业降低安装成本&#xff0c;提高设备性能的创新解决方案。 【全球认证&#xff0c;品质保障】ATV320 系列秉持施耐德…...

Dynamo:Amazon 的高可用键值仓储

大家觉得有意义和帮助记得及时关注和点赞!!! Dynamo 是 Amazon 的高可用分布式键值存储&#xff08;key/value storage&#xff09;系统。这篇论文发表 的时候&#xff08;2007&#xff09;它还只是一个内部服务&#xff0c;现在&#xff08;改名为 DynamoDB&#xff09;已经发…...

前端开发 -- 自动回复机器人【附完整源码】

一&#xff1a;效果展示 本项目实现了一个简单的网页聊天界面&#xff0c;用户可以在输入框中输入消息&#xff0c;并点击发送按钮或按下回车键来发送消息。机器人会根据用户发送的消息内容&#xff0c;通过关键字匹配来生成自动回复。 二&#xff1a;源代码分享 <!DOCTYP…...

离散数学 群(半群,群,交换群,循环群,对称群,置换群,置换,交代群,轮换)详细,复习笔记

半群: 设G是一个非空集合&#xff0c;若为G上的二元代数运算&#xff0c;且满足结合律&#xff0c;则称该代数系统(G,)为半群 性质:非空,封闭,结合律 独异点: 含有单位元的半裙 练习题&#xff1a; 例:设S是一个非空集合&#xff0c;p(S)是S的幂集&#xff0c;∩和U是p(S…...

Android Java 版本的 MSAA OpenGL ES 多重采样

最近多次被小伙伴问到 OpenGL 多重采样&#xff0c;其实前面文章里多次讲过了&#xff0c;就是构建2个缓冲区&#xff0c;多重采样缓冲区和目标解析缓冲区。 代码流程 // Framebuffer IDs private int msaaFBO; private int msaaColorBuffer; private int msaaDepthBuffer;pr…...

学习笔记之初识HALCON

目录 一、概要 二、数据结构 1、图像Image 2、Region区域 3、XLD 三、图像预处理 1、图像的变换与校正 2、图像增强 四、图像的形态学处理 1、边界提取 2、孔洞填充 3、骨架 五、图像金字塔 六、区域分割 1、区域生长 2、区域分裂与合并 七、边缘检测 1、Pre…...

嵌入式硬件杂谈(七)IGBT MOS管 三极管应用场景与区别

引言&#xff1a;在现代嵌入式硬件设计中&#xff0c;开关元件作为电路中的重要组成部分&#xff0c;起着至关重要的作用。三种主要的开关元件——IGBT&#xff08;绝缘栅双极型晶体管&#xff09;、MOSFET&#xff08;金属氧化物半导体场效应晶体管&#xff09;和三极管&#…...

【Rust自学】7.1. Package、Crate和定义Module

喜欢的话别忘了点赞、收藏加关注哦&#xff0c;对接下来的教程有兴趣的可以关注专栏。谢谢喵&#xff01;(&#xff65;ω&#xff65;) 7.1.1. Rust的代码组织 代码组织主要包括&#xff1a; 那些细节可以对外暴露&#xff0c;而哪些细节是私有的在作用域内哪些名称有效… …...

【已解决】pyinstaller打包ico图片报错:OSError: [WinError 225] 无法成功完成操作,因为文件包含病毒或潜在的垃圾软件。

起因&#xff1a; pyinstaller加上 --icon 参数打包时报错。 命令如下&#xff1a; 解决&#xff1a; 关闭 Windows 的病毒防护即可&#xff0c;步骤如下。 点屏幕右下角通知栏&#xff0c;进入“病毒和威胁防护”&#xff1a; 打开&#xff1a; 关闭实时保护&#xff08…...

广东粤万润与时序数据库TDengine携手打造智慧酒店新未来:数据驱动智能化转型

在智能化转型浪潮席卷全球的当下&#xff0c;智慧酒店行业已然成为推进智能生活应用的先锋领域。从智能照明到环境监测&#xff0c;从安防系统到沉浸式影音娱乐&#xff0c;智慧酒店通过技术赋能为用户提供了更加舒适、高效且个性化的服务体验。然而&#xff0c;随着设备的增多…...

基于云计算的分布式文件存储系统设计与实现

基于云计算的分布式文件存储系统设计与实现 第一章 绪论 1.1 研究背景及意义 随着互联网技术的飞速发展&#xff0c;云计算作为一种新兴的计算模式&#xff0c;以其弹性伸缩、按需分配和成本效益高等特点&#xff0c;逐渐成为信息技术领域的研究热点。它为大数据处理、高性能…...

基于顺序表实现队列循环队列的处理

文章目录 1.假溢出的现象2.循环队列3.顺序表实现队列架构4.顺序表模拟实现队列5.设计循环队列&#xff08;校招难度&#xff09; 1.假溢出的现象 下面的这个就是我们的假溢出的这个现象的基本的来源&#xff1a; 我们的这个队列里面是有9个位置的&#xff0c;我们知道这个队列…...

leecode377.组合总和IV

本题其实是多重背包问题&#xff0c;对于价值和重量都是nums[i]的的物品&#xff0c;求装满这个容量为4的背包共有多少种排列方式 如果是组合问题&#xff0c;那么遍历顺序是先物品后背包&#xff0c;这样能保证物品按从小到大顺序依次放置&#xff0c;对于实例1求出来为4&…...

变量与数据类型 - 整型、浮点型、字符型等

引言 在编程中&#xff0c;变量和数据类型是基础中的基础。理解它们如何工作以及如何正确使用它们对于编写高效且无误的代码至关重要。本文将详细介绍 C 中的几种基本数据类型&#xff1a;整型、浮点型、字符型等&#xff0c;并通过实例帮助读者更好地理解和掌握这些概念。 一…...

selenium学习笔记(二)

文章目录 前言设计模式POMPOM概念POM优势POM设计原则POM的实现 selenium的常用操作处理动态元素截图操作勾选复选框多层框架/窗口定位操作下拉框上传文件操作处理弹窗切换窗口拖拽操作 如何处理浏览器驱动更新导致的问题selenium与网站监控监听网页内容变化监控网络请求 seleni…...

vue和uniapp中,点击按钮 传递当前item对象,并从selectData数组中删除该条item数据

在 Vue 中,可以通过点击按钮传递 item 对象,并从 selectData 数组中删除该条数据。可以使用 Array.prototype.filter() 方法来实现这一点。以下是一个示例: 说明 数据结构:selectData 是一个包含多个对象的数组,每个对象都有 id 和 name 属性。渲染列表:使用 v-for 指令…...

双柱渐变图背景图

option {backgroundColor: #1b2735,tooltip: {//提示框组件trigger: axis,//触发类型 柱状图axisPointer:{type:shadow} //触发效果 移动上去 背景效果}, xAxis: [//x轴{type: category,//坐标轴类型 离散data: [1月, 2月, 3月, 4月, 5月, 6月, 7月, 8月],//数据axisTick:f…...

OpenHarmony怎么修改DPI密度值?RK3566鸿蒙开发板演示

本文介绍在开源鸿蒙OpenHarmony系统下&#xff0c;修改DPI密度值的方法&#xff0c;触觉智能Purple Pi OH鸿蒙开发板演示&#xff0c;搭载了瑞芯微RK3566四核处理器&#xff0c;Laval鸿蒙社区推荐开发板&#xff0c;已适配全新开源鸿蒙OpenHarmony5.0 Release系统&#xff0c;适…...

KylinOS V10 SP3下编译openGauss与dolphin插件

编译环境 KylinOS v10 sp3gcc 7.3.0make 4.3opengauss 5.0.0 mkdir -p /data/opengauss cd /data/opengauss git clone https://gitee.com/opengauss/openGauss-server.git git clone https://gitee.com/opengauss/Plugin.git wget -c https://opengauss.obs.cn-south-1.myhu…...

【入门】买杯子

描述 小明去商店买杯子&#xff0c;他想买价格在 10 到 20 元之间的杯子&#xff08;含 10 元和 20 元&#xff09;&#xff0c;他看到货架上有 3 个不同价格的杯子&#xff0c;请问最终他买了几个杯子&#xff0c;总共花了多少钱&#xff1f; 比如&#xff1a;货架上有如下的…...

VIVO C++开发面试题及参考答案

面向过程与面向对象的区别,面向对象后的好处 面向过程编程主要关注的是程序的流程,它将一个问题分解为一系列的步骤,通过函数来实现这些步骤,数据和操作这些数据的函数是分离的。例如,在一个简单的计算学生成绩平均值的程序中,我们可能会有一些函数来输入成绩、计算总和、…...

虚拟化 | Proxmox VE 8.x 开源的虚拟化平台快速上手指南

[ 知识是人生的灯塔,只有不断学习,才能照亮前行的道路 ] 0x00 简介说明 前言简述 描述:作为一个爱折腾的IT打工佬,时刻以学习各类新技术新知识为目标,这不正好有一台部署了VMware vSphere ESXi 虚拟化环境的服务器,由于正好安装其系统的磁盘有坏道,经常导致使用 ESXi 异…...

【原创学习笔记】近期项目中使用的西门子V20变频器总结(下篇)

上一篇我们简单介绍了下现场的变频器&#xff0c;现在我们来聊聊如何用手机控制变频器。 手机控制变频器的前提是变频器上必须安装智能模块&#xff0c;现场并为安装此模块&#xff0c;故不作考虑。 下面介绍一下如何实现手机或者电脑控制变频器 首先如果存在485通信&#x…...

idea 8年使用整理

文章目录 前言idea 8年使用整理1. 覆盖application配置2. 启动的时候设置编辑空间大小&#xff0c;并忽略最大空间3. 查询类的关系4. 查看这个方法的引用关系5. 查看方法的调用关系5.1. 查看被调用关系5.2. 查看调用关系 6. 方法分隔线7. 选择快捷键类型8. 代码预览插件9. JReb…...

Bluetooth Spec【0】蓝牙核心架构

蓝牙核心系统由一个主机、一个主控制器和零个或多个辅助控制器组成蓝牙BR/ EDR核心系统的最小实现包括了由蓝牙规范定义的四个最低层和相关协议&#xff0c;以及一个公共服务层协议&#xff1b;服务发现协议&#xff08;SDP&#xff09;和总体配置文件要求在通用访问配置文件&a…...

PlantUML 入门使用指南

PlantUML 入门使用指南 一、PlantUML介绍二、PlantUML的用途三、PlantUML的语法及示例3.1 用例图&#xff08;Use Case Diagram&#xff09;3.2 类图&#xff08;Class Diagram&#xff09;3.3 对象图&#xff08;Object Diagram&#xff09;3.4 序列图&#xff08;Sequence Di…...

QT:一个TCP客户端自动连接的测试模型

版本 1:没有取消按钮 测试效果&#xff1a; 缺陷&#xff1a; 无法手动停止 测试代码 CMakeLists.txt cmake_minimum_required(VERSION 3.19) project(AutoConnect LANGUAGES CXX)find_package(Qt6 6.5 REQUIRED COMPONENTS Core Widgets Network)qt_standard_project_setup(…...

IOS safari 播放 mp4 遇到的坎儿

起因 事情的起因是调试 IOS 手机下播放服务器接口返回的 mp4 文件流失败。对于没调试过移动端和 Safari 的我来说着实费了些功夫&#xff0c;网上和AI也没有讲明白。好在最终大概理清楚了&#xff0c;在这里整理出来供有缘人参考。 问题 因为直接用 IOS 手机的浏览器打开页面…...

LLM常见面试题(26-30题)--langchain篇

26&#xff0c;什么是langchain? 一个局域语言模型的框架&#xff0c;用于构建聊天机器人、生成式回答、摘要等功能。 核心思想是将不同的组件“链”在一起&#xff0c;连接大语言模型和外部资源&#xff0c;以创建更高级的语言模型应用。使得开发人员可以快速开发原型系统和…...

【Python运维】构建基于Python的自动化运维平台:用Flask和Celery

《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门! 解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 在现代IT运维中,自动化运维平台扮演着至关重要的角色,它能够显著提高运维效率,减少人为错误,并且增强系统的可维护性。本文将引导读者如…...

socket编程(C++/Windows)

相关文章推荐&#xff1a; Socket 编程基础 面试官&#xff0c;不要再问我三次握手和四次挥手 TCP的三次握手与四次挥手 参考视频&#xff1a; https://www.bilibili.com/video/BV1aW4y1w7Ui/?spm_id_from333.337.search-card.all.click TCP通信流程 服务端 #include<…...

Spring Boot介绍、入门案例、环境准备、POM文件解读

文章目录 1.Spring Boot(脚手架)2.微服务3.环境准备3.1创建SpringBoot项目3.2导入SpringBoot相关依赖3.3编写一个主程序&#xff1b;启动Spring Boot应用3.4编写相关的Controller、Service3.5运行主程序测试3.6简化部署 4.Hello World探究4.1POM文件4.1.1父项目4.1.2父项目的父…...

【hackmyvm】deba靶机wp

tags: HMVnodejs反序列化CVE-2017-5941wine命令定时任务 1. 基本信息^toc 文章目录 1. 基本信息^toc2. 信息收集2.1. 端口扫描2.2. 目录扫描 3. nodejs反序列化 (CVE-2017-5941)4. www-data提权low用户5. 定时任务提权6. wine命令 提权root6.1. 利用CS获取root 靶机链接 http…...

新浪微博大数据面试题及参考答案(数据开发和数据分析)

介绍一下你所掌握的计算机网络和操作系统相关知识 计算机网络:计算机网络是将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统。我掌握了网络协议…...

去除 el-input 输入框的边框(element-ui@2.15.13)

dgqdgqdeMac-mini spid-admin % yarn list --pattern element-ui yarn list v1.22.22 └─ element-ui2.15.13 ✨ Done in 0.23s.dgqdgqdeMac-mini spid-admin % yarn list vue yarn list v1.22.22 warning Filtering by arguments is deprecated. Please use the pattern opt…...

Qt 应用程序转换为服务

一、在 Windows 上将 Qt 应用程序转换为服务 方法1&#xff1a; 创建一个 Windows 服务应用程序&#xff1a; Windows 服务应用程序是一个没有用户界面的后台进程&#xff0c;通常由 Win32 Service 模板创建&#xff0c;或者直接编写 main() 函数以实现服务逻辑。 修改 Qt 应…...

C/C++ 数据结构与算法【树和森林】 树和森林 详细解析【日常学习,考研必备】带图+详细代码

一、树的存储结构 1&#xff09;双亲表示法实现&#xff1a; 定义结构数组存放树的结点&#xff0c;每个结点含两个域: 数据域&#xff1a;存放结点本身信息。双亲域&#xff1a;指示本结点的双亲结点在数组中的位置。 特点&#xff1a;找双亲简单&#xff0c;找孩子难 C语…...

潇洒郎:部署Dify, 安装Ollama,Ollama下载模型,Dify配置模型

Ollama 1、安装ollama Windows版本下载&#xff1a;2024WindowsOllama最新0.5.4版本资源-CSDN文库, 下载速度超快&#xff0c;官网太慢了 双击安装&#xff0c;安装成功后&#xff0c;托盘区有Ollama图标 右键View logs打开目录 C:\Users\Administrator\AppData\Local\Oll…...

如何在 Linux 中设置 SSH 免密码登录

一般情况下&#xff0c;我们通过一台 Linux 服务器远程另外一台服务器时&#xff0c;每次远程都需要输入对端机器的密码。 ssh root192.168.21.20 有没有这样一种情况&#xff0c;我们不用输入密码就可以远程别的服务器呢&#xff1f; 答案是肯定的&#xff0c;如果我们在 Li…...

网络安全词云图与技术浅谈

网络安全词云图与技术浅谈 一、网络安全词云图生成 为了直观地展示网络安全领域的关键术语&#xff0c;我们可以通过词云图&#xff08;Word Cloud&#xff09;的形式来呈现。词云图是一种数据可视化工具&#xff0c;它通过字体大小和颜色的差异来突出显示文本中出现频率较高…...

Linux | Ubuntu零基础安装学习cURL文件传输工具

目录 介绍 检查安装包 下载安装 手册 介绍 ‌cURL是一个利用URL语法在命令行下工作的文件传输工具&#xff0c;首次发行于1997年‌‌12。cURL支持多种协议&#xff0c;包括FTP、FTPS、HTTP、HTTPS、TFTP、SFTP、Gopher、SCP、Telnet、DICT、FILE、LDAP、LDAPS、IMAP、POP3…...

重启ubuntu服务器,如何让springboot服务自动运行

文章目录 1. 使用 systemd 服务步骤&#xff1a; 2. 使用 cron 的 reboot 任务步骤&#xff1a; 3. 使用 init.d 脚本&#xff08;适用于较旧版本&#xff09;步骤&#xff1a; 推荐方案 为了确保在重启Ubuntu服务器后&#xff0c;让springboot的服务test.jar象 nohup java -ja…...

MySQL 查询大偏移量(LIMIT)问题分析

大偏移量查询缓慢?LIMIT: 会进行两步操作 性能消耗在哪里了?OFFSET操作问题 2 LIMIT 操作 如何优化? 大偏移量查询缓慢? 示例:(假设age字段有索引) SELECT * FROM test WHERE age>18 LIMIT 10000000 ,10;分析MySQL的 LIMIT 10000000 , 10 LIMIT: 会进行两步操作 OFF…...

深入探究C++pow函数的优势和劣势 原理

优势 功能强大 支持多种数据类型&#xff1a; C 的pow()函数在<cmath>头文件中定义&#xff0c;它能够灵活地处理不同的数据类型。对于整数类型&#xff0c;如int、long long等&#xff0c;它能准确地计算幂次方。以计算棋盘上的麦粒数为例&#xff0c;传说国际象棋棋盘…...

Vue中动态样式绑定+CSS变量实现切换明暗主题功能——从入门到进阶

1.直接借助Vue的动态绑定样式绑定 Vue动态样式绑定 在Vue中&#xff0c;动态样式绑定是一种强大的功能&#xff0c;它允许开发者根据数据的变化动态地更新元素的样式。以下是对Vue动态样式绑定的详细知识梳理与详解&#xff1a; 一、基础知识 Vue的动态样式绑定主要通过v-b…...

Linux 硬盘扩容 分区 挂载

Linux 硬盘扩容 分区 & 挂载 1. 添加分区 1.1. 查看新添加的硬盘 fdisk -l假设当前未挂载的盘符是/dev/sdb&#xff0c;后文中所有操作都按挂载/dev/sdb 操作 1.2. 分区管理 小硬盘 fdisk /dev/sdb大硬盘&#xff08;2TB以上&#xff09; gdisk /dev/sdb1.3. 编辑分…...