【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 表达式,指定返回类型为 YourClass
        var 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 表达式,指定返回类型为 YourClass
        var 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 });
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

qemu 共享内存设备——ivshmem

文章目录 背景简单使用参考 背景 vshmem是QEMU提供的一种宿主机与虚拟机之间或多个虚拟机之间共享内存的特殊设备。它有两种形式: ivshmem-plain: 简单的共享内存区域ivshmem-doorbel: 除了共享内存&#xff0c;还能提供基于中断的通信机制 这种设备在虚拟机内部表现为PCI设…

dolphinscheduler服务注册中心源码解析(三)RPC提供者服务整合注册中心注册服务实现源码

RPC提供者服务整合注册中心注册服务实现源码 1.概述2.源码解读思路3.实现2.1.应用服务的RPC服务接口定义2.1.1.MasterServer应用中提供的RPC接口服务2.1.2.WorkerServer应用中提供的RPC接口服务2.2.应用服务的RPC服务接口实现2.2.1.MasterServer应用中提供的RPC接口服务实现类2…

若依的RBAC权限控制框架

若依权限管理框架 Spring Security介绍 Spring Security是spring的权限控制框架&#xff0c;主分为 认证 和 授权认证&#xff1a;是否能进入&#xff08;登录&#xff09;授权&#xff1a;是否有权限访问对应的资源&#xff08;controller能否访问&#xff09; Spring Securit…

Scala_【1】概述

第一章 语言特点环境搭建(Windows)idea编写scalaHelloWorld注意事项 Scala是一门以Java虚拟机&#xff08;JVM&#xff09;为运行环境并将面向对象和函数式编程的最佳特性结合在一起的静态类型编程语言 语言特点 Scala是一门多范式的编程语言&#xff0c;Scala支持面向对象和函…

sqoop抽数报错Every derived table must have its own alias

sqoop抽数报错Every derived table must have its own alias 报错如下&#xff1a; ERROR manager.SqlManager: Error executing statement: java.sql.SQLSyntaxErrorException: Every derived table must have its own alias 修改前脚本&#xff1a; –query "select * …

大小鼠智能热板仪 智能冷板仪~根据实验需求和方向选择“冷”or“热”

冷板仪的工作原理 SS-I5IO56IO48O 冷板仪主要通过提供一个可调节温度的冷板&#xff08;通常为金属地板&#xff09;&#xff0c;其温度设定在低温范围内&#xff08;如5℃&#xff09;&#xff0c;用于模拟冷刺激引起的疼痛反应。实验时&#xff0c;动物被放置在冷板上&…

VMware vCenter保姆级安装部署(VMware VCenter Nanny Level Installation and Deployment)

VMware vCenter保姆级安装部署教程 VMware vCenter‌是由VMware开发的一款虚拟化管理平台&#xff0c;主要用于管理和监控虚拟化环境中的虚拟机、主机和存储资源。它提供了一个集中控制的平台&#xff0c;简化了虚拟化基础设施的管理工作&#xff0c;提高了资源利用率和灵活性…

WebGIS实战开源项目:智慧机场三维可视化(学习笔记)

From&#xff1a;新中地 1.简介 智慧机场解决方案&#xff0c;基于数字化大平台&#xff0c;融合AI、大数据、IoT、视频云、云计算等技术&#xff0c;围绕机场“运控、安防、服务”三大业务领域&#xff0c;构建“出行一张脸”及“运行一张图”两大场景化解决方案。 https://…

玩转OCR | 探索腾讯云智能结构化识别新境界

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀ 玩转OCR 腾讯云智能结构化识别产品介绍服务应用产品特征行业案例总结 腾讯云智能结构化识别 腾讯云智能结构化OCR产品分为基础版与高级版&am…

【论文阅读笔记】Scalable, Detailed and Mask-Free Universal Photometric Stereo

【论文阅读笔记】Scalable, Detailed and Mask-Free Universal Photometric Stereo 前言摘要引言Task 相关工作方法SDM-UniPS预处理尺度不变的空间光特征编码器像素采样变压器的非局部交互 PS-Mix数据集 实验结果训练细节评估和时间&#xff1a; 消融实验定向照明下的评估没有对…

自动控制系统综合与LabVIEW实现

自动控制系统综合是为了优化系统性能&#xff0c;确保其可靠性、稳定性和灵活性。常用方法包括动态性能优化、稳态误差分析、鲁棒性设计等。结合LabVIEW&#xff0c;可以通过图形化编程、高效数据采集与处理来实现系统综合。本文将阐述具体方法&#xff0c;并结合硬件选型提供实…

VUE 3.0 如何新建项目 详细教程 附环境搭建 推荐

本人新入手一台电脑&#xff0c;需要安装各种环境配置&#xff0c;顺便把过程记录一下&#xff0c;方便自己以后查看&#xff0c;也欢迎大家参考交流。 目录 一、环境搭建&#xff1a; 1.Node.js安装 2.国内淘宝镜像设置 3.安装vue 环境 二、新建vue项目 1.vue脚手架新建…

牛客网刷题 ——C语言初阶——BC114 小乐乐排电梯

1.牛客网 &#xff1a;BC114 小乐乐排电梯 题目描述&#xff1a; 小乐乐学校教学楼的电梯前排了很多人&#xff0c;他的前面有n个人在等电梯。电梯每次可以乘坐12人&#xff0c;每次上下需要的时间为4分钟&#xff08;上需要2分钟&#xff0c;下需要2分钟&#xff09;。请帮助…

UE5 渲染管线 学习笔记

兰伯特 SSS为散射的意思 带Bias的可以根据距离自动切换mip的卷积值 而带Level的值mipmaps的定值 #define A8_SAMPLE_MASK .a 这样应该就很好理解了 这个只采样a通道 带Level的参考上面的 朝左上和右下进行模糊 带Bias参考上面 随机数 4D 3D 2D 1D

‘vite‘ 不是内部或外部命令,也不是可运行的程序

报错&#xff1a;执行 npm run dev时&#xff0c;提示’vite’ 不是内部或外部命令&#xff0c;也不是可运行的程序 解决&#xff1a;执行 npm install -g vite 报错&#xff1a;导入vite后再次执行npm run dev&#xff0c;报错failed to load config from E:\eclipseWP\test1…

gitlab克隆仓库报错fatal: unable to access ‘仓库地址xxxxxxxx‘

首次克隆仓库&#xff0c;失效了&#xff0c;上网查方法&#xff0c;都说是网络代理的问题&#xff0c;各种清理网络代理后都无效&#xff0c;去问同事&#xff1a; 先前都是直接复制的网页url当做远端url&#xff0c;或者点击按钮‘使用http克隆’ 这次对于我来说有效的远端u…

apisix docker 安装

git clone https://github.com/apache/apisix-docker.git cd apisix-docker/example nano docker-compose 主要修改这里ETCD_ADVERTISE_CLIENT_URLS: "http://192.168.31.160:2379" docker compose -p docker-apisix up -d#安装apisix-dashboard docker pull apache/…

相机雷达外参标定综述“Automatic targetless LiDAR–camera calibration: a survey“

相机雷达外参标定综述--Automatic targetless LiDAR–camera calibration: a survey 前言1 Introduction2 Background3 Automatic targetless LiDAR–camera calibration3.1 Information theory based method(信息论方法)3.1.1 Pairs of point cloud and image attributes(属性…

第13篇 冒泡排序__ARM C语言<二>

Q&#xff1a;如何设计ARM C语言程序对数组进行降序排列&#xff1f; A&#xff1a;基本原理也和Nois II C语言程序一样&#xff1a;通过不断的比较和交换数组中的数据元素&#xff0c;最终使得最大的数据“冒泡”排到到数组最末&#xff0c;并逐步缩小待排序的范围直到所有数…

Pytorch | 利用AI-FGTM针对CIFAR10上的ResNet分类器进行对抗攻击

Pytorch | 利用AI-FGTM针对CIFAR10上的ResNet分类器进行对抗攻击 CIFAR数据集AI-FGTM介绍算法流程初始化迭代更新&#xff08; t 0 t 0 t0 到 T − 1 T - 1 T−1&#xff09;迭代完成 AI-FGTM代码实现AI-FGTM算法实现攻击效果 代码汇总aifgtm.pytrain.pyadvtest.py 之前已经…