• 知乎问题:.NET AOT编译后能替代C++吗?


    标题上的Native库是指:Native分为静态库(

    作者:nscript
    链接:https://www.zhihu.com/question/536903224/answer/2522626086


     image

    (1)开发 NDK 库有人进行尝试:NativeAOT-AndroidHelloJniLib (https://github.com/josephmoresena/NativeAOT-AndroidHelloJniLib) 通过修改 .Net Runtime 来生成 Android 下的 NDK Native 库。希望后续官方能直接支持。

    (2)Remobjects Elements (https://www.remobjects.com/elements/) 收费工具。可以采用 C# 语言开发 NDK Native 库,限制是不能自由使用 Core CLR,而是使用 Remobjects 的平台相关库 island 和跨平台库 RTL,RTL 库和 Core CLR 的相关类型接口相似。

    Remobjects Elements 也可以用 C# 开发 wasm 模块,试用了下,满小巧的,gzip 下可以做到低于 1M,性能测试大约是 .net 6 的1/4-1/5。同上面一样,库这块会受到限制。

    Remobjects Elements 的思路蛮有意思的,可以用 C#[或 Oxygene(Object Pascal), Swift, Java, Go or Mercury (VB)] 来写各种库或应用程序。Swift 语言的免费,其他的收费。可以用这些语言写native 程序、 .net 程序、 jvm 程序 ……

    ----

    补充一下,这是个很值得探讨的问题,我一直在尝试用 csharp 代替 cpp。很多地方可以直接替代掉,但也遇到了一些问题:

    (1)写底层算法或库的话,而调用者各种语言都有,csharp的,vb的,java 的,delphi 的都碰到过。那时的工作流程是,csharp 写算法,验证之后,再根据对方需求,改成 cpp。有 AOT 之后,这种情况可以避免掉。

    (2)移动开发:安卓开发底层的库,参考资料太少。比如,开发个 sdk,给 java 调用,xamarin 资料太少,解决方案也不通用。

    AOT 工具链完善后,对我来说,可以解决很多问题:

    (1)写底层库:可以完全放心大胆的用 csharp 写底层库了,jit 模式下快速开发,aot 模式发布。csharp 的生产力比 cpp 高太多,构建系统也比 cmake 好使的多。我现在正在尝试优化 csharp 脚本开发 aot dll 的开发流程,目前还没完全完成,但也挺舒服的,以一个最简单的例子来说明,

    lib.csx:

    using System.Runtime.InteropServices;
    
    [UnmanagedCallersOnly(EntryPoint = "add")]
    public static int Add(int a, int b)
    {
        return a + b;
    }
    
    [DllImport("pack/out/lib.dll")]
    private static extern int add(int a, int b);
    
    int result = add(2,4);
    Console.WriteLine(result);
    

    一行命令就编译成 dll 了,win10下是964 k。

    nscript pack --aot --lib lib.csx

    再用下面指令调用脚本:

    nscript .\lib.csx

    输出:

    6

    这种开发模式可比写 cpp 舒服太多了。目前 aot 工具链还不够完善,但是开发起来难度不大,就是工作量的问题。比如,根据代码,直接生成各个语言的调用封装,生成文档 ......

    这样一来,就可以用 csharp 快速开发出底层库,生成动态链接库、静态链接库给桌面用,给服务器用,给移动设备用。底层库一般不牵扯到ui,其通用性极强。做 android 的 ndk 开发太折腾,cpp 开发,jni 调用,调试麻烦得很。

    这也可以解决 csharp 这块防止反编译的问题,发布时也可以 UI 层用 jit 跑,底层用 aot 跑来保护代码。

    (2)开发小工具

    我造过一个轮子,把 avalonia 的控件库的核心给拆出来,用 direct2d 来绘制,弄了一些基本的控件,写简单的桌面程序,aot 之后尺寸可以控制在 4M,如果写一些小工具还是可以的。

    再比如说,如果想发布一些 server 端小工具,以 http 方式提供服务,jit 模式下,用 asp.net 来做,单个文件发布压缩之后可以做到20-30M, 用 EmbedIO 来写的话,单个文件发布,win下11M,linux 下 13M。EmbedIO用了反射,aot 我没配好,没跑出来,根据经验的话,aot 应该可以做到 2-4 M。不过,11M 也够用了,来看看用脚本写的代码:

    #r "nuget: EmbedIO, 3.4.3"
    
    using EmbedIO;
    using EmbedIO.WebApi;
    using EmbedIO.Actions;
    using EmbedIO.Files;
    
    WebServer CreateWebServer(string url)
    {
        var server = new WebServer(o => o
                .WithUrlPrefix(url)
                .WithMode(HttpListenerMode.EmbedIO))
            .WithLocalSessionManager()
            .WithStaticFolder("/static/", "./webroot", true, m => m.WithContentCaching(true)) // Add static files after other modules to avoid conflicts
            .WithModule(new ActionModule("/api", HttpVerbs.Get, HandleApi))
            .WithModule(new ActionModule("/", HttpVerbs.Any, ctx => ctx.SendDataAsync(new { Message = "Hello!" })))
            ;
        return server;
    }
    
    Task HandleApi(IHttpContext ctx)
    {
        return ctx.SendDataAsync("api");
    }
    
    //@main
    var url = "http://*:5000/";
    var server = CreateWebServer(url);
    server.RunAsync();
    Console.ReadKey();
    

    所以,工具链完善后,用 csharp 写东西很爽的:

    (1)写完之后,AOT一下,给各个语言用 <--> 对标 cpp;

    (2)写完之后,打包个几M 的小东西,扔服务器跑 <--> 是不是很像 golang?

    (3)不建项目,像我上面那样用脚本写 <--> python;

    (4)正常使用 <--> java;

    (5)上 blazor <--> js。

    除此之外,还有很新东西可以玩的 ......

    ----

    一些场景替代不了:

    (1)带 gc 的 .net aot,最小尺寸差不多1M,对于有的场景这个尺寸过大。比如说,对于插件系统,每个插件1M,100个就100M,过大,并且全部加载的话,有100个gc在跑,浪费。不知有没技术让100个插件共享一个 gc。虽然可以不开gc,但这样,就只是个大号的C了。

    (2)对实时性要求高的场景,因为有gc存在会受到限制。

    其他场景可以当有 gc 的 cpp 用,应该可以达到 cpp 80%+的性能。

    其实现在jit,aot以及源生cpp性能都差不了太多,我做过密集计算的测试,细节忘记了,只记得是个 float 密集计算,java 的性能大于csharp和cpp。后来分析,jvm 做了向量化并行处理,csharp和cpp没有做。改csharp代码手动用simd,最后性能略高于Java。

    aot的除了启动快,还有其他好处:(1)代码很难反编译;(2)尺寸小。

    假设你要写个东西,给java调用或python调用,用 jit 的话,得几十M,aot 的话,可以做到 1M。这样的话,很多用cpp写的sdk,可以用csharp来写,aot编译成动态链接库,提供给上层用。

    而不开gc的话,你可以就当他是个C语言的方言。

    Windows以lib后缀名,Linux以a后缀 名)和动态库(Windows以dll为后缀名,Linux以so后缀名。 本文顺序先从生成Native程序.然后是动态库,最后是静态库。

  • 相关阅读:
    LeetCode算法二叉树—LCR 194. 二叉树的最近公共祖先
    Redux Toolkit
    【ArcGIS微课1000例】0051:Geodatabase子类型操作全解
    LVS负载均衡及LVS-NAT模式
    【正则】二代身份证正则表达式
    【学习记录】实例分割的发展与区别
    密度图计数
    如何优化Flask-Report报表的性能和加载速度
    MindSpore数据集加载-GeneratorDataset卡住、卡死
    nacos配置中心使用教程
  • 原文地址:https://www.cnblogs.com/shanyou/p/16671516.html