前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >试试将.NET7编译为WASM在Docker上运行

试试将.NET7编译为WASM在Docker上运行

作者头像
InCerry
发布2023-03-08 15:56:59
8570
发布2023-03-08 15:56:59
举报
文章被收录于专栏:InCerryInCerry

之前有听到说 Docker 支持 Wasmtime 了,刚好.NET7 也支持 WASM,就带大家来了解一下这个东西,顺便试试它怎么样。

因为WASM(WebAssembly) 一开始是一个给浏览器的技术,比起 JS 解释执行,WASM 能用于提升浏览器的用户体验,因为在一些场景中它有着比 JS 更好的性能。

大家可以将 WASM 理解为 C#的 MSIL 或者 Java 的字节码,它并不是二进制代码,还是会由 JIT 编译执行,JIT 有很多优化,另外大多数场景也只会 JIT 一次,加上省略了 JS 加载,语法分析各种的过程,才会有着比 JS 更好的性能。

另外因为 WASM 是中间码的格式,所以理论上任何语言 C#、RUST、Java、Go 都可以将代码编译为 WASM,然后放到浏览器中执行。比如 C#火热的 Blazor 项目,就是将 C#编译为 WASM,然后使 C#代码能在浏览器中运行。

另外聊一聊WASI(WebAssembly System Interface),我们知道 WASM 有着不错的可移植性和安全性(目前浏览器运行都是沙箱运行,对于权限管控很严格),那么就有一群大佬就说,我们是不是能脱离浏览器单独运行 WASM 程序呢?于是就产生了一个标准的系统接口,大家都按照这样的方式来生成 WASM,调用系统 API,然后我们开发一个 Runtime,让大家的 WASM 程序都能在这上面运行。

举个不严谨的例子说明一下 WASI 就是比如:

  • C# => MSIL => CLR(Mono、CoreCLR)
  • Java => 字节码 => JVM(HotSpot VM、ZingVM) 而现在我们可以:
  • C# => WASM => WASI(wasmtime、wasmedge)。

各位应该就明白了,WASI 其实就是个运行时的规范,大家编译成 WASM 放上去就能跑。

所以现在对于它的观点就是,觉得它在 Server 后端领域目前来说不是一个很价值的东西,因为可移植性好的语言比比皆是,比如 C#、Java、Go 等等。

拿性能来说,对于这样的中间语言性能无关就是 JIT 和 GC,WASI 的 JIT 和 GC 能做的像 C#、Java 这样的 JIT、GC 性能那么好吗?这个目前来说是存在疑问的,至少在短时间内很难追平其它平台十多年的优化。

再说 WASM 的另一个优点,就是体积小和启动快,现在 C#支持 NativeAOT、Java 有 GraalVM、Go 和 Rust 之类的本身就是编译型语言,启动速度和体积都很不错,WASM 在这个方面其实不占优势。

.NET 编译为 WASM

好了,言归正传,我们来试试.NET7 上面的 WASM。.NET7 目前已经发布,我们需要使用最新的版本,如下图所示:

然后我们创建一个简单的控制台项目,用于输出斐波那契数列和执行耗时,代码如下所示 (这并不性能最优的实现,只是这样子实现简单)

代码语言:javascript
复制
using System.Diagnostics;

namespace PublishDotNetToWASM;

public static class Program
{
    public static void Main()
    {
        // warm
        ulong sum = 0;
        foreach (var i in Fibonacci().Take(1000))
        {
            sum += i;
        }

        // run
        sum = 0;
        var sw = Stopwatch.StartNew();
        foreach (var i in Fibonacci().Take(100000))
        {
            sum += i;
        }
        sw.Stop();
        Console.WriteLine($"Result:{sum}, Timespan:{sw.ElapsedTicks} Ticks");
    }

    private static IEnumerable<ulong> Fibonacci()
    {
        ulong current = 1, next = 1;

        while (true)
        {
            yield return current;
            next = current + (current = next);
        }
    }
}

接下来为了将.NET 程序发布成 WASM,我们需要安装Wasi.Sdk预览包,这个预览包是Steve Sanderson大佬做的支持,可以将.NET 程序编译为 WASM,截止至目前版本信息如下所示:

代码语言:javascript
复制
<PackageReference Include="Wasi.Sdk" Version="0.1.2-preview.10061" />

运行dotnet publish -c Release命令,将我们的应用程序发布为 WASM 格式,在发布过程中,需要下载MinGW作为编译器,网络环境不好的同学,需要想办法访问国外网站,稍微等待一会就顺利的发布成功了:

运行 WASM 程序

此时我们可以安装一下Wasmtime来执行我们的程序,通过https://wasmtime.dev/下载安装:

然后就可以直接使用wasmtime命令运行我们的程序,我分别使用wasmtimedotnet运行了我们的程序:

可见目前来说 WASM 的性能还是惨不忍睹的,等一等后续的优化吧。

将.NET 发布到 Docker WASI

再来看看我们的 Docker,对于 Docker 支持 WASI 我感到并不意外,因为 Docker 的容器化对于直接执行的 WASM 来说还是比较重,支持它是一个拓宽影响力的好事。具体的执行模型如下所示,对于 WASM 应用有着不同的执行方式。不再使用runc而是wasmedge

wasmedge也是一个实现了 WASI 标准的 WASM 运行时,和上文提到的 wasmtime 一样。

要实现在 Docker 上运行 WASM 程序需要安装 Docker 的预览版,链接https://docs.docker.com/desktop/wasm/

然后我们整一个 Dockerfile,我们直接依赖 scratch 镜像即可,因为它不需要其它的基础镜像(暂时我没有使用.NET7 的多段构建镜像,听大佬说目前貌似有问题)。

代码语言:javascript
复制
FROM scratch
COPY ./bin/Release/net7.0/PublishDotNetToWASM.wasm /PublishDotNetToWASM.wasm
ENTRYPOINT [ "PublishDotNetToWASM.wasm" ]

再使用下面的命令构建 Docker 镜像,由于是 wasm 镜像,所以需要带额外的参数。

代码语言:javascript
复制
docker buildx build --platform wasi/wasm32 -t publishdotnettowasm .

可以看到打包出来的镜像是非常小的,只有 3.68MB。

运行的话也很简单,用下方的命令即可,需要指定 runtime 为io.containerd.wasmedge.v1,另外也需要指定 paltform。

代码语言:javascript
复制
docker run --rm --name=publishdotnettowasm --runtime=io.containerd.wasmedge.v1 --platform=wasi/wasm32 publishdotnettowasm

我把 dotnet 原生运行、wasmtime 运行、docker WASI 运行都跑了一下,可以发现目前来说是惨不忍睹。

总结

以上就是如何将.NET7 程序发布到 WASM,然后在 Docker 最新的 WASI 中运行的样例,目前来看基本的运行都已经 OK,不过正如我前面提到的,现在性能还是太受影响了。

这不仅仅是在.NET 平台上,其它语言 Rust、C、C++编译为 WASM 上都有明显的性能下降。

思来想去可能在一些插件化和不需要性能很好的场景 WASI 会比较用。不过这些都需要时间慢慢见证,毕竟存在即合理,像 JS 这样的语言不一样好好的?

我们可以拭目以待,看看 WASM/WASI 会不会给我们带来其它惊喜,期待后续 Steve Sanderson 大佬和 WASM 社区的相关优化。

源码链接

https://github.com/InCerryGit/PublishDotNetToWASM

参考文献

https://www.docker.com/blog/docker-wasm-technical-preview/

https://www.zhihu.com/question/304577684/answer/1961085507

https://arghya.xyz/articles/webassembly-wasm-wasi/

https://laurentkempe.com/2022/10/31/experimenting-with-dotnet-7-wasm-and-wasi-on-docker/

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-11-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 InCerry 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • .NET 编译为 WASM
  • 运行 WASM 程序
  • 将.NET 发布到 Docker WASI
  • 总结
  • 源码链接
  • 参考文献
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档