Nim 枚举类型 对性能的影响
Nim 枚举类型 对性能的影响
继上一篇文章《Nim 概念 Concept 对性能的影响》后,我在想,既然 method 虚方法造成性能的影响很大,那么有没有更快的方法实现,当然是有的,那就是枚举类型。
Enum Type
与很多的新设计的一样,Nim语言也内置了枚举类型,比如下面的代码:
type
ValueGetterKind = enum
vkClass1,
vkClass2
ValueGetter2 = ref object
sharedField : int32
case kind:ValueGetterKind
of vkClass1:someField1 : int32
of vkClass2:someField2 : int32
正如你看到的,在Nim语言中,通过为类型增加一个枚举字段(这里是kind),就可以为不同的类型定义不同的字段了,当然,你也可以定义共享的字段(这里例子的 sharedField)。
官方的例子中,演示了更复杂的情况,比如 多个类型公用相同的字段,或者定义多个字段。
# This is an example how an abstract syntax tree could be modelled in Nim
type
NodeKind = enum # the different node types
nkInt, # a leaf with an integer value
nkFloat, # a leaf with a float value
nkString, # a leaf with a string value
nkAdd, # an addition
nkSub, # a subtraction
nkIf # an if statement
Node = ref object
case kind: NodeKind # the `kind` field is the discriminator
of nkInt: intVal: int
of nkFloat: floatVal: float
of nkString: strVal: string
of nkAdd, nkSub:
leftOp, rightOp: Node
of nkIf:
condition, thenPart, elsePart: Node
var n = Node(kind: nkFloat, floatVal: 1.0)
# the following statement raises an `FieldDefect` exception, because
# n.kind's value does not fit:
n.strVal = ""
性能对比
接着我们之前的例子,我们看看在泛型的情况下,调用枚举类型对性能究竟影响有多少。
import std/[times],std/random
type
IValueGetter = concept s
s.getValue(int32) is int64
MyTestClass[T] = object
valueGetter: T
proc run[T: IValueGetter](this: MyTestClass[T]): int64 =
var r = 0i64
let n = high(int32) - rand(100).int32
for i in 0 ..< n:
r += this.valueGetter.getValue(i)
return r
type
ValueGetterKind = enum
vkClass1,
vkClass2,
#vkClass3,
ValueGetter2 = ref object
sharedField : int32
case kind:ValueGetterKind
of vkClass1:someField1 : int32
of vkClass2:someField2 : int32
#of vkClass3:someField3 : int32
func getValue(this: ValueGetter2, index: int32): int64 =
#return index.int64 + 7i64
case this.kind:
of vkClass1:
result = index.int64 + 9i64
of vkClass2:
result = index.int64 + 11i64
#of vkClass3:
# result = index.int64 + 17i64
proc measureTime(caption: string, procToMeasure: proc(): int64) =
var startTime = cpuTime()
let r = procToMeasure()
var endTime = cpuTime()
echo caption, " time = ", endTime - startTime, " result = ", r
# 运行测试
proc main() =
randomize()
let t7 = MyTestClass[ValueGetter2](valueGetter : ValueGetter2(kind:vkClass1, someField1:9))
measureTime("ValueGetter2:1 ", proc ():int64 = t7.run())
let t8 = MyTestClass[ValueGetter2](valueGetter : ValueGetter2(kind:vkClass2, someField2:11))
measureTime("ValueGetter2:2 ", proc ():int64 = t8.run())
#let t9 = MyTestClass[ValueGetter2](valueGetter : ValueGetter2(kind:vkClass3, someField3:11))
#measureTime("ValueGetter2:3 ", proc ():int64 = t9.run())
when isMainModule:
main()
在我的机器中,测试结果如下(均使用release编译,下同):
ValueGetter2:1 time = 0.725 result = 2305842980222664759
ValueGetter2:2 time = 1.967 result = 2305842982370148375
我们看到,如果是判断分支的第一个,性能与本地调用稍差(0.7对比0.4),但与虚方法的5秒已经好太多。
细心的你,可能已经注意到我给的代码注释掉了第三种类型vkClass3,那么是不是作为分支的第三种情况,会更慢?让我们取消几个分支的注释,看看结果:
ValueGetter2:1 time = 1.300 result = 2305842894323320179
ValueGetter2:2 time = 1.345 result = 2305842842783714180
ValueGetter2:3 time = 1.295 result = 2305842993107566484
意不意外?第一个分支竟然变慢了,而后两个分支变快了,最后一个分支还稍稍快一点点。是否说明nim语言编译为2个枚举类型和3个枚举类型,使用了不同的编译代码? 让我们从nim生成的c语言源码验证这件事。
// 这是2个枚举的代码
N_LIB_PRIVATE N_NIMCALL(NI64, getValue__demo50_u28)(tyObject_ValueGetter2colonObjectType___liWfIs6eMPnbT0BuR4LSgg* this_p0, NI32 index_p1) {
NI64 result;
result = (NI64)0;
switch ((*this_p0).kind) {
case ((tyEnum_ValueGetterKind__tsIJjFnfs8zo9caQCLYJn1A)0):
{
result = (NI64)(((NI64) (index_p1)) + IL64(9));
}
break;
case ((tyEnum_ValueGetterKind__tsIJjFnfs8zo9caQCLYJn1A)1):
{
result = (NI64)(((NI64) (index_p1)) + IL64(11));
}
break;
}
return result;
}
// 这是三个枚举的代码
N_LIB_PRIVATE N_NIMCALL(NI64, getValue__demo50_u30)(tyObject_ValueGetter2colonObjectType___liWfIs6eMPnbT0BuR4LSgg* this_p0, NI32 index_p1) {
NI64 result;
result = (NI64)0;
switch ((*this_p0).kind) {
case ((tyEnum_ValueGetterKind__tsIJjFnfs8zo9caQCLYJn1A)0):
{
result = (NI64)(((NI64) (index_p1)) + IL64(9));
}
break;
case ((tyEnum_ValueGetterKind__tsIJjFnfs8zo9caQCLYJn1A)1):
{
result = (NI64)(((NI64) (index_p1)) + IL64(11));
}
break;
case ((tyEnum_ValueGetterKind__tsIJjFnfs8zo9caQCLYJn1A)2):
{
result = (NI64)(((NI64) (index_p1)) + IL64(17));
}
break;
}
return result;
}
可以看出,代码完全是一样的,可能是编译器做了手脚。当然,我也测试了更多枚举的可能,比如7种,我发现所有分支时间都变长了(达到2秒),但总体是比虚方法好的。
共享的字段
在 getValue 方法中,如果你没有对类型进行判断,那么实际测试的成绩和静态方法调用是一样的,这可以被利用到我们面向对象编程中,经常用到的基类统一实现的场景。
总结
在 nim 编程中,简单的派生关系可以使用 枚举类型来提高性能。
Nim 枚举类型 对性能的影响的更多相关文章
- (转)类(class)和结构(struct)的区别是什么?它们对性能有影响吗?.NET BCL里有哪些是类(结构),为什么它们不是结构(类)?在自定义类型时,您如何选择是类还是结构?
转自:http://blog.csdn.net/lingxyd_0/article/details/8695747 类(class)和结构(struct)的区别是什么?它们对性能有影响吗?.NET B ...
- 一天五道Java面试题----第九天(简述MySQL中索引类型对数据库的性能的影响--------->缓存雪崩、缓存穿透、缓存击穿)
这里是参考B站上的大佬做的面试题笔记.大家也可以去看视频讲解!!! 文章目录 1.简述MySQL中索引类型对数据库的性能的影响 2.RDB和AOF机制 3.Redis的过期键的删除策略 4.Redis ...
- Enum(枚举类型)的基本应用
一.前言 在我们日常的开发过程中,我们经常定义使用常量:在Effective Java建议用枚举来替换常量的使用,提高我们代码的质量,总结一下枚举定义常量的基本使用 二.枚举类型说明 1.枚 ...
- 【转】Android中的内存管理--不错不错,避免使用枚举类型
原文网址:http://android-performance.com/android/2014/02/17/android-manage-memory.html 本文内容翻译自:http://dev ...
- List是线程安全的吗?如果不是该怎么办呢?安全的List对性能的影响有多大呢?
测试条件: 开启2个并行执行任务,往同一个list对象写入值 测试代码: ; static List<int> list = new List<int>(); static v ...
- Effective Java 第三版——34. 使用枚举类型替代整型常量
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- 结构体struct、联合体union、枚举类型enum
1.c语言中的类型 1)内置类型——char,short,int,float,double: 2)用户自定义类型(UDT)——struct结构体,union联合体,enum枚举类型 2.内存对齐 2. ...
- Python 中的枚举类型~转
Python 中的枚举类型 摘要: 枚举类型可以看作是一种标签或是一系列常量的集合,通常用于表示某些特定的有限集合,例如星期.月份.状态等. 枚举类型可以看作是一种标签或是一系列常量的集合,通常用于表 ...
- 从一个int值显示相应枚举类型的名称或者描述
我正在做一个出入库管理的简单项目,在Models里定义了这样的枚举类型 public enum InOrOut { [Description("出库")] Out = , [Des ...
- C语言--enum,typedef enum 枚举类型详解
原文:http://z515256164.blog.163.com/blog/static/32443029201192182854300/ 有改动 C语言详解 - 枚举类型 注:以下全部代码的执行环 ...
随机推荐
- 带你读论文丨S&P2019 HOLMES Real-time APT Detection
本文分享自华为云社区<[论文阅读] (09)S&P2019 HOLMES Real-time APT Detection(溯源图)>,作者: eastmount . 摘要 本文提出 ...
- 【page cache】简介
目录 page cache 直接 IO 与 缓存 IO Linux IO 栈 Linux 中的具体实现 相关结构体 超级块 super_block 索引节点 inode 文件 file 目录项 den ...
- 【Visual Studio 使用技巧分享】任务列表的使用
前言 Visual Studio 开发工具的熟练使用,能够潜在的提升我们工作效率,而且一些开发技巧的使用,会让我们的工作显得那么方便快捷.那么你知道VS中有哪些你不知道的使用小技巧呢?接下来,我们就来 ...
- 2023-09-01:用go语言编写。给出两个长度均为n的数组, A = { a1, a2, ... ,an }, B = { b1, b2, ... ,bn }。 你需要求出其有多少个区间[L,R]
2023-09-01:用go语言编写.给出两个长度均为n的数组, A = { a1, a2, ... ,an }, B = { b1, b2, ... ,bn }. 你需要求出其有多少个区间[L,R] ...
- 银河麒麟使用kickstart二次打包制作安装镜像ISO
系统:银河麒麟 V10 SP2 服务器:百信恒山 TS02F-F30 安装方式:服务器挂载ISO镜像进行安装 1.安装 mkisofs 软件包: #yum install genisoimage 2. ...
- EarthChat SignalR原理讲解
SignalR原理讲解 SignalR是什么? SignalR 是 Microsoft 开发的一个库,用于 ASP.NET 开发人员实现实时 web 功能.这意味着服务端代码可以实时地推送内容到连接的 ...
- C#/.NET/.NET Core优秀项目和框架2023年9月简报
前言 公众号每月定期推广和分享的C#/.NET/.NET Core优秀项目和框架(公众号每周至少推荐两个优秀的项目和框架当然节假日除外),公众号推文有项目和框架的介绍.功能特点以及部分截图等(打不开或 ...
- ElasticSearch系列——文档操作
文章目录 Elasticsearch的增删查改(CURD) 一 CURD之Create 二 CURD之Update 三 CURD之Delete 四 CURD之Retrieve Elasticsearc ...
- 期中考试成绩出来了。分数在70~80是等级B。
#多输入 空格分割a = input()b = a.split()c = list(map(int, b))print(c) 等级B 描述 期中考试成绩出来了.分数在70-80是等级B. 输入 请 ...
- ModelScope
欢迎来到ModelScope平台!本篇文章介绍如何快速开始使用ModelScope平台上的模型,包括所需的基础概念,环境安装,模型推理和训练的快速实践示例. 如何开始# 如果你是新手,想快速体验产品, ...