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语言详解 - 枚举类型 注:以下全部代码的执行环 ...
随机推荐
- .NET Core多线程 (4) 锁机制
合集:.NET Core多线程温故知新 .NET Core多线程(1)Thread与Task .NET Core多线程(2)异步 - 上 .NET Core多线程(3)异步 - 下 .NET Core ...
- 让C#调用vue组件里的方法
前言:web页面开发时采用的是vue开发的,后台语言是C# 需求:后台需要通过浏览器调用vue组件的方法 c# 可以调用xxx.html 中的script引用的js中定义的方法是可以调用的, 之前c# ...
- 微服务集成redis并通过redis实现排行榜的功能
默认你已经看过我之前的教程了,并且拥有上个教程完成的项目, 之前的教程 https://www.cnblogs.com/leafstar/p/17638933.html 由于redis的安装网上教程很 ...
- 在centos7.X下安装tomcat – 东凭渭水流
发布于 14 分钟前 1 次阅读 1.下载tomcat,并用工具将tomcat传输到linux中 mkdir /oopt/tomcat 2.解压tomcat文件 tar -zxvf apache-t ...
- VictoriaLogs:一款超低占用的 ElasticSearch 替代方案
背景 前段时间我们想实现 Pulsar 消息的追踪流程,追踪实现的效果图如下: 实现其实比较简单,其中最重要的就是如何存储消息. 消息的读取我们是通过 Pulsar 自带的 BrokerInterce ...
- WPF学习 - 自定义Panel
WPF中的Panel(面板),是继承自FrameworkElement的抽象类,表示一个可以用来排列子元素的面板. 在WPF中,一种预设了几种常用的面板,如Grid.StackPanel.WrapPa ...
- OpenCASCADE 显示对象设置不可选中
原有的选中模式代码: static Standard_Integer SelectionMode (const TopAbs_ShapeEnum theShapeType) { switch (the ...
- KRPANO开发拍摄拼图视频常用软件分享
KRPano开发拍摄拼图视频常用软件分享,包含了KRPano开发,拼图,视频等软件. 包括如下软件: 全景照片拼接,全景照片查看,全景视频拼接,全景视频查看,全景视频插件,全景漫游制作,KRPano资 ...
- linux上搭建Nacos集群(步骤详细,linux小白也能搞定)
(1)nacos官网:https://github.com/alibaba/nacos/releases/tag/1.2.1下载nacos安装包到window本地(后缀为tar.zip) (2)在li ...
- windows10 jdk下载及环境配置
一.环境准备 windows10 系统 jdk 各种版本(配置大同小异) 二.下载并安装jdk 下载地址:http://www.oracle.com/technetwork/java/javase/ ...