https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=bf2d79be35661ce80cbdf2be405e258f
每加一层调用,就加128个字节
Ext Link: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=bf2d79be35661ce80cbdf2be405e258f
1
共 11 条评论, 1 页
评论区
写评论好的
--
👇
catsalwaysmeow: 抱歉我不能加陌生人好友哦。我也在社区二群,有问题可以在群里讨论呀。
抱歉我不能加陌生人好友哦。我也在社区二群,有问题可以在群里讨论呀。
--
👇
宁: 加个q 《393零93零》 一起学习探讨
嗯嗯,弄清楚就好了。没想到想将值直接放到堆上仍然依赖release的优化,这个例子构造得真棒。
--
👇
宁: 明白,看看我的测试,确实像你说的,即使用 Box::pin,变量在stack中也会爆 https://play.rust-lang.org/?version=stable&mode=release&edition=2018&gist=3f447dc77d000564c11072131c0dca1c
明白,看看我的测试,确实像你说的,即使用 Box::pin,变量在stack中也会爆 https://play.rust-lang.org/?version=stable&mode=release&edition=2018&gist=3f447dc77d000564c11072131c0dca1c
--
👇
catsalwaysmeow: 找到原因了。我之前的想法有一点问题,注意不要被误导了!因为
Drop
的存在,局部变量都会被放到状态机中。如果不关心某一个变量的Drop
,可以通过添加大括号改变它的作用域,这样子它就有机会被排除到状态机之外了。参考:https://tmandry.gitlab.io/blog/posts/optimizing-await-2/#liveness-and-drop
--
👇
catsalwaysmeow: 我也测试了一下。如果没有用
Box::pin
包起来,SoBigAField
的确在调用栈中(栈顶地址与栈底地址之间)。作用域没有跨越.await
的变量,的确没有被保存在状态机中,也就没有增加impl Future
的大小。但「作用域」意味着必须用大括号把它包含起来,否则,即使对它的使用没有跨越.await
,它也会被包括到状态机中。有可能是因为编译器还不够聪明,也可能是因为存在其它我没有注意到的考量。找到原因了。我之前的想法有一点问题,注意不要被误导了!因为
Drop
的存在,局部变量都会被放到状态机中。如果不关心某一个变量的Drop
,可以通过添加大括号改变它的作用域,这样子它就有机会被排除到状态机之外了。参考:https://tmandry.gitlab.io/blog/posts/optimizing-await-2/#liveness-and-drop
--
👇
catsalwaysmeow: 我也测试了一下。如果没有用
Box::pin
包起来,SoBigAField
的确在调用栈中(栈顶地址与栈底地址之间)。作用域没有跨越.await
的变量,的确没有被保存在状态机中,也就没有增加impl Future
的大小。但「作用域」意味着必须用大括号把它包含起来,否则,即使对它的使用没有跨越.await
,它也会被包括到状态机中。有可能是因为编译器还不够聪明,也可能是因为存在其它我没有注意到的考量。我也测试了一下。如果没有用
Box::pin
包起来,SoBigAField
的确在调用栈中(栈顶地址与栈底地址之间)。作用域没有跨越.await
的变量,的确没有被保存在状态机中,也就没有增加impl Future
的大小。但「作用域」意味着必须用大括号把它包含起来,否则,即使对它的使用没有跨越.await
,它也会被包括到状态机中。有可能是因为编译器还不够聪明,也可能是因为存在其它我没有注意到的考量。--
👇
宁: 理解了,我做个实验看是不是这样
--
👇
catsalwaysmeow: 我也在学习async/await,还有许多东西没有弄明白,下面的理解可能有错哦。
编译器为async函数生成的匿名结构(返回的impl Future)储存了跨越了
.await
的变量(SoBigAField
),以及必要的标志。原则上,它只是一个普通的结构,具体被放置在哪里取决于「调用者」如何处理它:如果「调用者」用
Box::pin
把它包了起来,那么它就在Allocator分配的内存中(通常是堆)。如果「调用者」只是将它赋值到了一个局部变量
local_future
中,分为两种情况。 如果local_future
在「调用者」的代码中被.await
了,那么local_future
会被放置在「调用者」返回的匿名结构中,它被放置在哪里又取决于「调用者」的「调用者」... 如果local_future
没有被.await
,那么它会被放置到「调用者」的调用栈中。理解了,我做个实验看是不是这样
--
👇
catsalwaysmeow: 我也在学习async/await,还有许多东西没有弄明白,下面的理解可能有错哦。
编译器为async函数生成的匿名结构(返回的impl Future)储存了跨越了
.await
的变量(SoBigAField
),以及必要的标志。原则上,它只是一个普通的结构,具体被放置在哪里取决于「调用者」如何处理它:如果「调用者」用
Box::pin
把它包了起来,那么它就在Allocator分配的内存中(通常是堆)。如果「调用者」只是将它赋值到了一个局部变量
local_future
中,分为两种情况。local_future
在「调用者」的代码中被.await
了,那么local_future
会被放置在「调用者」返回的匿名结构中,它被放置在哪里又取决于「调用者」的「调用者」...local_future
没有被.await
,那么它会被放置到「调用者」的调用栈中。--
👇
宁: 没注意,box::pin是一个方案,不用关Sleep的align,多谢多谢! 另外,我一直有一个疑问,future在运行的时候 async_fn_aligned_structure 里的 SoBigAField 是放在栈上的,还是在堆上的。
--
👇
宁: 厉害!厉害! align(128)只是为了提高性能吧。如果不用的话,只是性能下降,没有其他副作用吧 有办法能关掉 Sleep 的align128吗,节省点空间
--
👇
catsalwaysmeow: 看起来是因为
Sleep
这个Future
内部存在一个align(128)
的字段。Sleep->TimerEntry->TimerShared->StateCell->CachePadded
手动对状态机里的字段设置
align(128)
也能得到类似的效果,参考async_fn_aligned_structure
。https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=58ca2b8568f4a1a5336c0801789f7af1
我也在学习async/await,还有许多东西没有弄明白,下面的理解可能有错哦。
编译器为async函数生成的匿名结构(返回的impl Future)储存了跨越了
.await
的变量(SoBigAField
),以及必要的标志。原则上,它只是一个普通的结构,具体被放置在哪里取决于「调用者」如何处理它:如果「调用者」用
Box::pin
把它包了起来,那么它就在Allocator分配的内存中(通常是堆)。如果「调用者」只是将它赋值到了一个局部变量
local_future
中,分为两种情况。local_future
在「调用者」的代码中被.await
了,那么local_future
会被放置在「调用者」返回的匿名结构中,它被放置在哪里又取决于「调用者」的「调用者」...local_future
没有被.await
,那么它会被放置到「调用者」的调用栈中。--
👇
宁: 没注意,box::pin是一个方案,不用关Sleep的align,多谢多谢! 另外,我一直有一个疑问,future在运行的时候 async_fn_aligned_structure 里的 SoBigAField 是放在栈上的,还是在堆上的。
--
👇
宁: 厉害!厉害! align(128)只是为了提高性能吧。如果不用的话,只是性能下降,没有其他副作用吧 有办法能关掉 Sleep 的align128吗,节省点空间
--
👇
catsalwaysmeow: 看起来是因为
Sleep
这个Future
内部存在一个align(128)
的字段。Sleep->TimerEntry->TimerShared->StateCell->CachePadded
手动对状态机里的字段设置
align(128)
也能得到类似的效果,参考async_fn_aligned_structure
。https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=58ca2b8568f4a1a5336c0801789f7af1
没注意,box::pin是一个方案,不用关Sleep的align,多谢多谢! 另外,我一直有一个疑问,future在运行的时候 async_fn_aligned_structure 里的 SoBigAField 是放在栈上的,还是在堆上的。
--
👇
宁: 厉害!厉害! align(128)只是为了提高性能吧。如果不用的话,只是性能下降,没有其他副作用吧 有办法能关掉 Sleep 的align128吗,节省点空间
--
👇
catsalwaysmeow: 看起来是因为
Sleep
这个Future
内部存在一个align(128)
的字段。Sleep->TimerEntry->TimerShared->StateCell->CachePadded
手动对状态机里的字段设置
align(128)
也能得到类似的效果,参考async_fn_aligned_structure
。https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=58ca2b8568f4a1a5336c0801789f7af1
厉害!厉害! align(128)只是为了提高性能吧。如果不用的话,只是性能下降,没有其他副作用吧 有办法能关掉 Sleep 的align128吗,节省点空间
--
👇
catsalwaysmeow: 看起来是因为
Sleep
这个Future
内部存在一个align(128)
的字段。Sleep->TimerEntry->TimerShared->StateCell->CachePadded
手动对状态机里的字段设置
align(128)
也能得到类似的效果,参考async_fn_aligned_structure
。https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=58ca2b8568f4a1a5336c0801789f7af1
看起来是因为
Sleep
这个Future
内部存在一个align(128)
的字段。Sleep->TimerEntry->TimerShared->StateCell->CachePadded
手动对状态机里的字段设置
align(128)
也能得到类似的效果,参考async_fn_aligned_structure
。https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=58ca2b8568f4a1a5336c0801789f7af1