本文主要是介绍2310d亚当1009,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
原文
考虑
缓存CTFE
结果的潜在新示例:只需在标准运行时
函数中,包装
它们即可.在模板实例
周围使用属性取器
,而不是声明变量.表明发射到目标文件
,而不是在导入
时重新计算.
ctfe缓存
SS
在Discord
聊天室发现了MartinNowak
在Phobos
中编写的一些旧代码,带有一条奇怪
的注释:它说它在自动返回
函数中,包装一些ctfe
,因此直到实际调用函数
时,才会在函数体
上运行语义
.
在dmd
中,有各种叫语义
可执行一大堆特别
是包括,在函数
中运行必要的CTFE
,并在函数体
中处理导入,甚至还会计算推导属性
等活动
的函数
.
函数
的语义族
一般是构建
中最昂贵
的部分之一(特别是包括CTFE
时),因此避免
它可节省大量时间.
然而,对缓存ctfe
,动(auto)
函数并不是特别有趣,因为无论是编译还是导入
,总是在调用
函数时处理它的主体
.
这与推导
属性起作用的原因相同,使用函数时必须处理主体
,因此不需要显式
告诉编译器属性
.也表明即使之前已完成
且结果
已在目标文件
中,使用
时也会重新处理
函数内的CTFE
.
仅导入自动
文件不会触发其函数体
中的CTFE
,但即使已预编译模块
,导入并调用
它时也会重新处理
.
即使只是导入
且从未使用过的全局变量
,也总是计算它,这是对全局变量
(不变
还是枚举
无区别)的改进,但它还不够好.
我想可导入一个函数
并调用
它,仍可用预编译
的CTFE
结果.
好吧,旧的代码注释和Walter
一贯说的话,这里
是推导
属性会损害编译速度
,这让我想到:是否现在可在导入
的非根
模块的函数体
上运行语义
.
我做了一个测试来调查:
//ctfe.d
template thing() {string helper() {string s;foreach(i; 0 .. 50000)s ~= "ok";return s;}enum thing = helper;
}
//immutable getThing2 = thing!();
//enum getThing2 = thing!();
string getThing() {//import ctfe3; int a = "foo";return thing!();
}
及主模块
:
//ctfe2.d
import ctfe;
void main() {string s = getThing();//enum foo = getThing() ~ "lol";
}
经过调整
,导入
模块中的追加
循环,要花一秒
的编译时间.编译速度
与构建行数
无关,而与你如何处理它们有关.
在dmd
(及LDC
和GDC
)中,CTFE
的~=
操作符有个可怕
的实现,所以使用
它,很容易破坏
你的编译时间.一般,应避免
使用它.
现在可通过观察编译时间
来判断是否运行CTFE
.很容易区分,一秒
构建与大约1/10
秒构建.
故意让int a="foo"
的类型不匹配
;或导入不存在
模块也是确认未运行语义
,也是在运行语义
时,生成这些错误
.
我在此注释
掉它们以编译
模块,如果不注释它,则仅导入
时不会生成
错误!
关键是,当前dmd
实现中,在本次导入
但未编译
的模块,即非根
模块中会完全跳过
非模板非自动返回的函数体
.
当然,会令牌化
它们,并至少
经过最低限度解析
,来知道函数
何时结束,但没有语义分析
,没有ctfe
,没有代码生成
,跳过了构建
中昂贵
部分.
但是,有时它们非常昂贵!getThing
中的该ctfe
就是一例,除非绝对必要
,否则确实不想再次运行语义
.我想我会修改推导属性
提案,以添加方法
来抑制
推导属性,并保留当前行为.
今天已解决di问题.
再次看测试:
template thing() {string helper() {string s;foreach(i; 0 .. 50000)s ~= "ok";return s;}enum thing = helper;
}
string getThing() {return thing!();
}
实际计算ctfe
,还有几层,与助手
函数一样:一个包装器模板
,然后是一个包装器标准函数
.它们类似,但一个在编译时
,一个在运行时
.
包装器模板
编译时缓存CTFE
结果.用相同参数
再次引用
模板时,编译器会从内存
缓存中拉回缓存结果
.
它还抑制生成助手函数
代码,避免
在目标文件中的运行时
使用,并避免编译器浪费时间
在上面生成代码
.
然后,包装器属性
,注意它有个显式返回类型
,导致在目标
文件中输出ctfe
结果,而下次
导入模块时,会跳过正文,不会再执行模板+ctfe
;相反从预编译
文件中引用
它.
但是,如果确实想用CTFE
的结果,函数体
仍在且可按需
使用,但要为每次编译
再支付CTFE
成本.
因此,它不会按单独编译CTFE
单元可重用
方式来缓存
它,但确实适合只是试
在代码中正常调用
函数的用户.
这是个相当不错
的结果,在今天编译器
中可用,且仅微小的调整了代码
.
单独编译
,最大好处
是,如果有非常昂贵
的东西及一个非常基本的公共接口
.
如果生成代码
来把Web
接口或脚本语言
粘合在一起,则归结
为在公共接口
中查找表
来生成函数,则可通过这些基本函数
来来再次生成构建代码
.
即使函数体
很昂贵,如果遵循上面
规则,则不会处理这些函数体
.
这篇关于2310d亚当1009的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!