通过解析库探究函数式抽象代价 ( ini 解析示例补充)
上一篇 用 HexColor 作为示例,可能过于简单
这里再补充一个 ini 解析的示例
由于实在写不动用其他库解析 ini 了, 春节都要过完了,累了,写不动了,
所以随意找了一份解析ini的库, 仅供参考,对比不准确,毕竟完整库包含了更多功能
先看看结果
BenchmarkDotNet v0.13.12, Windows 11 (10.0.22631.3085/23H2/2023Update/SunValley3)
Intel Core i7-9750H CPU 2.60GHz, 1 CPU, 12 logical and 6 physical cores
.NET SDK 8.0.200
[Host] : .NET 8.0.2 (8.0.224.6711), X64 RyuJIT AVX2
DefaultJob : .NET 8.0.2 (8.0.224.6711), X64 RyuJIT AVX2
| Method | Mean | Error | StdDev | Gen0 | Gen1 | Allocated |
|---|---|---|---|---|---|---|
| Hande_Ini | 567.9 ns | 11.24 ns | 21.66 ns | 0.2851 | - | 1.75 KB |
| RuQu_Ini | 1,691.4 ns | 33.48 ns | 64.51 ns | 0.4177 | - | 2.56 KB |
| IniDataParser | 4,836.3 ns | 94.44 ns | 167.87 ns | 1.1215 | 0.0076 | 6.91 KB |
// * Legends *
Mean : Arithmetic mean of all measurements
Error : Half of 99.9% confidence interval
StdDev : Standard deviation of all measurements
Gen0 : GC Generation 0 collects per 1000 operations
Gen1 : GC Generation 1 collects per 1000 operations
Allocated : Allocated memory per single operation (managed only, inclusive, 1KB = 1024B)
1 ns : 1 Nanosecond (0.000000001 sec)
总结
delegate肯定会有调用消耗,ini 场景使用的函数远多于 HexColor ,可以看到消耗大了很多
先看来自 dotnet Microsoft.Extensions.Configuration 中解析 ini 的代码
public static IDictionary<string, string?> Read(string content)
{
var data = new Dictionary<string, string?>(StringComparer.OrdinalIgnoreCase);
using (var reader = new StringReader(content))
{
string sectionPrefix = string.Empty;
while (reader.Peek() != -1)
{
string rawLine = reader.ReadLine()!; // Since Peak didn't return -1, stream hasn't ended.
string line = rawLine.Trim();
// Ignore blank lines
if (string.IsNullOrWhiteSpace(line))
{
continue;
}
// Ignore comments
if (line[0] is ';' or '#' or '/')
{
continue;
}
// [Section:header]
if (line[0] == '[' && line[line.Length - 1] == ']')
{
// remove the brackets
sectionPrefix = string.Concat(line.AsSpan(1, line.Length - 2).Trim(), ConfigurationPath.KeyDelimiter);
continue;
}
// key = value OR "value"
int separator = line.IndexOf('=');
if (separator < 0)
{
throw new FormatException(rawLine);
}
string key = sectionPrefix + line.Substring(0, separator).Trim();
string value = line.Substring(separator + 1).Trim();
// Remove quotes
if (value.Length > 1 && value[0] == '"' && value[value.Length - 1] == '"')
{
value = value.Substring(1, value.Length - 2);
}
if (data.ContainsKey(key))
{
throw new FormatException(key);
}
data[key] = value;
}
}
return data;
}
再来看看部分函数语义优化的代码
public class Ini
{
private static Ini instance = new Ini();
public Func<IPeeker<char>, bool> WhiteSpace = Chars.IngoreWhiteSpace.Map(i => i > 0);
public Func<IPeeker<char>, bool> Comment = Chars.In(";#/").Delimited(Chars.NotCRLF.ToSlice().Opt(), Chars.IsCRLF, "Comment not right").Map((c, x, y, z) => c);
public Func<IPeeker<char>, string> SectionName = Chars.Is('[').Delimited(Chars.Not(']').ToSlice().Once("Section name is required."), Chars.Is(']'), "Section name must end with ']'").Map((c, x, y, z) => y?.ToString());
public Func<IPeeker<char>, string> Key = Chars.Not('=').ToSlice().Once("key is required.").Map(i => i.ToString());
public Func<IPeeker<char>, char> Separater = Chars.Is('=').Once("Section name is required.");
public Func<IPeeker<char>, string> Value = Chars.NotCRLF.ToSlice().Once("value is required.").Map(i =>
{
var v = i.ToString().Trim();
return v.StartsWith('"') ? v[1..^1] : v;
});
public IDictionary<string, string> ParseString(string content)
{
var input = Input.From(content);
var dict = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
while (input.TryPeek(out var v))
{
if (!(WhiteSpace(input) || Comment(input) || Section(input, dict)))
{
throw new NotSupportedException(v.ToString());
}
}
return dict;
}
public bool SectionContentEnd(IPeeker<char> input)
{
return !input.TryPeek(out var v) || v is '[';
}
public bool Section(StringPeeker input, Dictionary<string, string> dict)
{
var name = SectionName(input);
if (name == null) return false;
while (!SectionContentEnd(input))
{
if (WhiteSpace(input) || Comment(input))
{
continue;
}
SectionKV(input, dict, name);
}
return true;
}
public void SectionKV(StringPeeker input, Dictionary<string, string> dict, string name)
{
var k = Key(input);
Separater(input);
var v = Value(input);
k = $"{name}:{k.Trim()}";
dict.Add(k, v.Trim());
}
public static IDictionary<string, string> Parse(string content)
{
return instance.ParseString(content);
}
}
最后截取 部分 ini 解析库的代码 仅供参考
public IniData Parse(string iniDataString)
{
IniData iniData = (Configuration.CaseInsensitive ? new IniDataCaseInsensitive() : new IniData());
iniData.Configuration = Configuration.Clone();
if (string.IsNullOrEmpty(iniDataString))
{
return iniData;
}
_errorExceptions.Clear();
_currentCommentListTemp.Clear();
_currentSectionNameTemp = null;
try
{
string[] array = iniDataString.Split(new string[2] { "\n", "\r\n" }, StringSplitOptions.None);
for (int i = 0; i < array.Length; i++)
{
string text = array[i];
if (text.Trim() == string.Empty)
{
continue;
}
try
{
ProcessLine(text, iniData);
}
catch (Exception ex)
{
ParsingException ex2 = new ParsingException(ex.Message, i + 1, text, ex);
if (Configuration.ThrowExceptionsOnError)
{
throw ex2;
}
_errorExceptions.Add(ex2);
}
}
if (_currentCommentListTemp.Count > 0)
{
if (iniData.Sections.Count > 0)
{
iniData.Sections.GetSectionData(_currentSectionNameTemp).TrailingComments.AddRange(_currentCommentListTemp);
}
else if (iniData.Global.Count > 0)
{
iniData.Global.GetLast().Comments.AddRange(_currentCommentListTemp);
}
_currentCommentListTemp.Clear();
}
}
catch (Exception item)
{
_errorExceptions.Add(item);
if (Configuration.ThrowExceptionsOnError)
{
throw;
}
}
if (HasError)
{
return null;
}
return (IniData)iniData.Clone();
}
完整代码参考 https://github.com/fs7744/ruqu
通过解析库探究函数式抽象代价 ( ini 解析示例补充)的更多相关文章
- 爬虫(五)—— 解析库(二)beautiful soup解析库
目录 解析库--beautiful soup 一.BeautifulSoup简介 二.安装模块 三.Beautiful Soup的基本使用 四.Beautiful Soup查找元素 1.查找文本.属性 ...
- 【开源】libinimini:适用于单片机的极简 ini 解析库
介绍说明 最近自己基于 XR872 在做一个小作品练习练习,具备可以配置的功能,选择了使用 ini 作为配置文件.我调研了网上常见的 ini 解析库,几乎都涉及到了 fopen()/fgets().. ...
- OpenStack配置解析库oslo.config的使用方法
OpenStack的oslo项目旨在独立出系统中可重用的基础功能,oslo.config就是其中一个被广泛使用的库,该项工作的主要目的就是解析OpenStack中命令行(CLI)或配置文件(.conf ...
- C++的Json解析库:jsoncpp和boost(转)
原文转自 http://blog.csdn.net/hzyong_c/article/details/7163589 JSON(JavaScript Object Notation)跟xml一样也是一 ...
- [转]C++的Json解析库:jsoncpp和boost
JSON(JavaScript Object Notation)跟xml一样也是一种数据交换格式,了解json请参考其官网http://json.org,本文不再对json做介绍,将重点介绍c++的j ...
- golang常用库:配置文件解析库-viper使用
一.viper简介 viper 配置解析库,是由大神 Steve Francia 开发,他在google领导着 golang 的产品开发,他也是 gohugo.io 的创始人之一,命令行解析库 cob ...
- Boost.JSON Boost的JSON解析库(1.75首发)
目录 目录 Boost的1.75版本新库 JSON库简介 JSON的简单使用 编码 最通用的方法 使用std::initializer_list json对象的输出 两种对比 解码 简单的解码 增加错 ...
- 解析库beautifulsoup
目录 一.介绍 二.遍历文档树 三.搜索文档树(过滤) 四.修改文档树 五.总结 一.介绍 Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的 ...
- Pugixml一种快速解析XML文件的开源解析库
Pugixml是一个轻量级的C++ XML开源解析库,DOM形式的解析器.接口和丰富的遍历和修改操作,快速的解析,此外支持XPath1.0实现数据查询,支持unicode编码: 使用Pugixml可通 ...
- Tomjson - 一个"短小精悍"的 json 解析库
Tomjson,一个"短小精悍"的 json 解析库,tomjson使用Java语言编写,主要作用是把Java对象(JavaBean)序列化为json格式字符串,将json格式字符 ...
随机推荐
- windows10/liunx创建空大文件
1.windows10创建空大文件打开cmd命令,进入需要创建文件的目录,使用以下命令创建 fsutil file createnew test001.txt 1073741824 最后的数字代表文件 ...
- 基于AHB_BUS的eFlash控制器的架构设计
eFlash控制器的架构设计 1.架构设计思路分析 1.1 含有的模块分析 eFlash控制器是一个基于AHB的slave,所以需要一个AHB_slave_if处理AHB的信号.AHB_slave_i ...
- VSCODE配置tasks.json
1.新建配置任务tasks.json 选择gcc.exe 可以在其中按需修改 { "version": "2.0.0", "tasks": ...
- linux环境C语言实现:h264与pcm封装成AVI格式
前言 拖了很久的AVI音视频封装实例,花了一天时间终于调完了,兼容性不是太好,但作为参考学习使用应该没有问题. RIFF和AVI以及WAV格式,可以参考前面的一些文章.这里详细介绍将一个H264视 ...
- [转帖]NET Framework 版本和依赖关系
https://learn.microsoft.com/zh-cn/dotnet/framework/migration-guide/versions-and-dependencies 每个版本的 . ...
- [转帖]Redhat 8 磁盘调度策略变化:NOOP改为NONE
说明 在 redhat 4/5/6/7版本中的NOOP调度策略,从8开始修改为NONE,官方解释: none Implements a first-in first-out (FIFO) schedu ...
- [转帖]Linux—vi/vim批量注释及取消注释
https://www.jianshu.com/p/45c252e9d2b6 应用场景 在开发场景中,经常遇到对一些配置文件进行注释,当然如果确定不用的时候我们可以通过vim中的D命令进行删除.当 ...
- 【转帖】读懂什么是RDMA
一.什么是RDMA1.RDMA主要体现 2.如何理解RDMA和TCP技术的区别?3.使用RDMA的好处包括: 二.什么是RoCE?1. RDMA协议包含:Infiniband(IB)2. 为什 ...
- [转帖]xfs_repair命令详解
https://bbs.qunyingkeji.com/2052/ 1.现状 目前网上出现大量的主机输入输出错误,原因是由于主机文件系统损坏.一线人员大部分采用的是umont 和 mount的方式恢复 ...
- [转帖]linux下 进程io队列,IO队列和IO调度
IO体系概览 先看看本文主题IO调度和IO队列处于整个IO体系的哪个位置,这个IO体系是非常重要的,了解IO体系我们可以对整个IO过程有个全面的认识.虽然一下两下并不清楚IO体系各个部分的细节,但是我 ...