首页 星云 工具 资源 星选 资讯 热门工具
:

PDF转图片 完全免费 小红书视频下载 无水印 抖音视频下载 无水印 数字星空

一个基于 SourceGenerator 生成 从 dbReader转换为 class 数据的性能测试实验

编程知识
2024年07月30日 16:28

好奇

SourceGenerator 出现开始,好几年了,虽然一直好奇用SourceGenerator 生成代码 与 emit 等动态生成的代码会有多少差距,

但是一直特别懒,不想搞

其实 dapper aot 项目做了类似事情,不过功能特别积极,还引用了实验特性,所以还是想更为简单客观对比

本次乘着自己暂时性不懒了,做了一个基于 SourceGenerator 生成 从 dbReader转换为 class 数据的测试

no generate code when

  • Generic Type (如果不用 emit 动态生成,还真无法处理未知类型 T)
  • Anonymous Type (SourceGenerator 生成时机要早于匿名类生成,所以还没机会生成)

generate code

具体怎么做的就这里不写了,感兴趣参考 https://github.com/fs7744/SlowestEM

生成的代码带有一定 db结果动态类型处理,以此更接近实际使用


// <auto-generated/>
#pragma warning disable 8019 //disable 'unnecessary using directive' warning
using System;
using System.Data;
using System.Runtime.CompilerServices;
using System.Collections.Generic;

namespace SlowestEM.Generator
{
    public static partial class Dog_Accessors
    {
        public static IEnumerable<BenchmarkTest.Dog> Read(IDataReader reader)
        {
            var s = new List<Action<BenchmarkTest.Dog, IDataReader>>(reader.FieldCount);
            for (int i = 0; i < reader.FieldCount; i++)
            {
                var j = i;
                switch (reader.GetName(j).ToLower())
                {
                    
                    case "age": 
                    {
                        // int?
                        
                        var needConvert = typeof(int) != reader.GetFieldType(i);
                        s.Add((d,r) => d.Age = DBExtensions.ReadToInt32Nullable(r,j,needConvert));
                         
                    }
                    break;
                    case "name": 
                    {
                        // string
                        
                        var needConvert = typeof(string) != reader.GetFieldType(i);
                        s.Add((d,r) => d.Name = DBExtensions.ReadToString(r,j,needConvert));
                         
                    }
                    break;
                    case "weight": 
                    {
                        // float?
                        
                        var needConvert = typeof(float) != reader.GetFieldType(i);
                        s.Add((d,r) => d.Weight = DBExtensions.ReadToFloatNullable(r,j,needConvert));
                         
                    }
                    break;
                    default:
                        break;
                }
            }
            while (reader.Read())
            {
                var d = new BenchmarkTest.Dog();
                foreach (var item in s)
                {
                    item?.Invoke(d,reader);
                }
                yield return d;
            }
        }
    }
}
            

测试结果

mock db, 避免 db层实现性能和没有正确处理数据类型装箱拆箱问题

[Benchmark(Baseline = true), BenchmarkCategory("1")]
public void SetClassFirst()
{
    Dog dog;
    try
    {
        connection.Open();
        var cmd = connection.CreateCommand();
        cmd.CommandText = "select ";
        using (var reader = cmd.ExecuteReader(CommandBehavior.Default))
        {
            if (reader.Read())
            {
                dog = new Dog();
                dog.Name = reader.GetString(0);
                dog.Age = reader.GetInt32(1);
                dog.Weight = reader.GetFloat(2);
            }
        }
    }
    finally
    {
        connection.Close();
    }
}

[Benchmark, BenchmarkCategory("1")]
public void DapperMappingFirst()
{
    var dogs = connection.QueryFirst<Dog>("select ");
}

[Benchmark, BenchmarkCategory("1")]
public void SourceGeneratorMappingFirst()
{
    Dog dog;
    try
    {
        connection.Open();
        var cmd = connection.CreateCommand();
        cmd.CommandText = "select ";
        using (var reader = cmd.ExecuteReader(CommandBehavior.Default))
        {
            dog = reader.ReadTo<Dog>().FirstOrDefault();
        }
    }
    finally
    {
        connection.Close();
    }
}

BenchmarkDotNet v0.13.12, Windows 10 (10.0.19045.4651/22H2/2022Update)
Intel Core i7-10700 CPU 2.90GHz, 1 CPU, 16 logical and 8 physical cores
.NET SDK 9.0.100-preview.5.24307.3
  [Host]     : .NET 8.0.6 (8.0.624.26715), X64 RyuJIT AVX2
  DefaultJob : .NET 8.0.6 (8.0.624.26715), X64 RyuJIT AVX2


Method Categories Mean Error StdDev Ratio RatioSD Gen0 Gen1 Allocated Alloc Ratio
SetClassFirst 1 实体 18.38 ns 0.378 ns 0.316 ns 1.00 0.00 0.0181 - 152 B 1.00
SourceGeneratorMappingFirst 1 实体 183.31 ns 3.525 ns 3.462 ns 9.98 0.14 0.0899 - 752 B 4.95
DapperMappingFirst 1 实体 1,336.69 ns 5.777 ns 5.121 ns 72.77 1.30 0.0343 - 288 B 1.89
SetClass 1000 实体 7,700.08 ns 87.311 ns 68.167 ns 1.00 0.00 6.7749 1.1139 56712 B 1.00
SourceGeneratorMapping 1000 实体 23,428.85 ns 262.698 ns 232.875 ns 3.04 0.03 6.8359 1.1292 57312 B 1.01
DapperMapping 1000 实体 48,880.92 ns 682.693 ns 533.002 ns 6.35 0.06 13.4888 2.1362 113048 B 1.99
From:https://www.cnblogs.com/fs7744/p/18332993
本文地址: http://shuzixingkong.net/article/602
0评论
提交 加载更多评论
其他文章 ambari2.8+ambari-metrics3.0+bigtop3.2编译、打包、安装
bigtop编译 资源说明: 软件及代码镜像 开发包镜像 github访问 编译相关知识 技术知识 bigtop编译流程及经验总结 各模块编译难度及大概耗时(纯编译耗时,不包含下载文件和排错时间) centos 真机编译branch-3.2 硬件说明: 编译步骤 下载代码并切换分支 国内镜像配置 基
ComfyUI插件:ComfyUI Impact 节点(四)
前言: 学习ComfyUI是一场持久战,而 ComfyUI Impact 是一个庞大的模块节点库,内置许多非常实用且强大的功能节点 ,例如检测器、细节强化器、预览桥、通配符、Hook、图片发送器、图片接收器等等。通过这些节点的组合运用,我们可以实现的工作有很多,例如自动人脸检测和优化修复、区域增强、
ComfyUI插件:ComfyUI Impact 节点(四) ComfyUI插件:ComfyUI Impact 节点(四) ComfyUI插件:ComfyUI Impact 节点(四)
使用Nginx Proxy Manager配置Halo的反向代理和申请 SSL 证书
本文介绍Nginx Proxy Manager配置Halo的反向代理和申请 SSL 证书,如需要了解Halo 2的安装,参考如何在Linux云服务器上通过Docker Compose部署安装Halo,搭建个人博客网站?。 目录安装Nginx Proxy ManagerNginx Proxy Mana
使用Nginx Proxy Manager配置Halo的反向代理和申请 SSL 证书 使用Nginx Proxy Manager配置Halo的反向代理和申请 SSL 证书 使用Nginx Proxy Manager配置Halo的反向代理和申请 SSL 证书
Known框架实战演练——进销存财务管理
本文介绍如何实现进销存管理系统的财务对账模块,财务对账模块包括供应商对账和客户对账2个菜单页面。供应商和客户对账字段相同,因此可共用一个页面组件类。 项目代码:JxcLite 开源地址: https://gitee.com/known/JxcLite 1. 配置模块 运行项目,在【系统管理-模块管理
前后端数据的交互--如何实现数据加密?--02
数据加密是保护数据安全的重要手段,通过加密技术,我们可以确保即使数据被窃取,也无法直接读取其中的信息。本文将介绍三种常见的加密方法:对称加密、非对称加密以及数据库加密,并展示如何在实际项目中实现这些加密技术。 1. 对称加密 对称加密算法使用相同的密钥进行加密和解密。AES(Advanced Enc
《花100块做个摸鱼小网站 · 序》灵感来源
序 大家好呀,我是summo,这次来写写我在上班空闲(摸鱼)的时候做的一个小网站的事。去年阿里云不是推出了个活动嘛,2核2G的云服务器一年只要99块钱,懂行的人应该知道这个价格在业界已经是非常良心了,虽然优惠只有一年,但是买一台用来学习还是非常合适的(优惠链接在这,需要自取)。 我也跟风买了一台,开
《花100块做个摸鱼小网站 · 序》灵感来源 《花100块做个摸鱼小网站 · 序》灵感来源 《花100块做个摸鱼小网站 · 序》灵感来源
火山引擎VeDI数据技术分享:两个步骤,为Parquet降本提效
本文将介绍字节跳动基于Parquet格式降本增效的技术原理和在具体业务中的实践,首先介绍了Parquet格式在字节跳动的应用,然后将结合具体的应用场景:小文件合并和列级TTL ,从问题产生的背景和解决问题的技术方案出发,介绍如何基于Parquet格式实现降本增效的目标。
火山引擎VeDI数据技术分享:两个步骤,为Parquet降本提效 火山引擎VeDI数据技术分享:两个步骤,为Parquet降本提效 火山引擎VeDI数据技术分享:两个步骤,为Parquet降本提效
汇编+qemu玩转控制台打印
有段时间开始对汇编感兴趣,也因此在写各种不同的demo,现在分享之前学习的成果,需要下载的东西有nasm和qemu-system-i386,看看枯燥的汇编能产生多大的能量。 先来复习一下通用寄存器: 8位通用寄存器: AL: 用于存储操作数低8位的数据寄存器。 AH: 用于存储操作数高8位的数据寄存
汇编+qemu玩转控制台打印 汇编+qemu玩转控制台打印