开启辅助访问
 找回密码
 注册帐号

扫一扫,访问微社区

蛮牛译馆

关注:592

当前位置:游戏蛮牛 技术专区 蛮牛译馆

查看: 2966|回复: 32

[外文翻译] 在Unity中Foreach循环的最佳优化

[复制链接]  [移动端链接]
排名
22361
昨日变化
43

21

主题

109

帖子

357

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
156801
好友
2
蛮牛币
585
威望
0
注册时间
2016-7-15
在线时间
179 小时
最后登录
2017-11-6
发表于 2017-5-18 13:42:52 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?注册帐号

x
本帖最后由 204有个大坑 于 2017-5-18 13:42 编辑

4411foreach-loop-optimization.png
目标:
这篇博客的主要目标是解释怎么避免在Unity中使用Foreach时占用过多内存。
这篇博客只是我们在Unity游戏优化方案系列中的一部分。如果你想学习怎样优化你的游戏,可以看
http://www.theappguruz.com/blog/unity-optimization-initiative
在游戏中没有发现一些小问题
遍历循环的时候有没有卡顿或者延迟?
是不是必须要遍历一些Gameobject?
如果你有注意到这些,那么你找对地方了!

通常,在游戏中出现卡顿/延迟是因为在单一帧中有太多的垃圾要回收。所以,在继续讲之前,我们先要理解什么是垃圾回收(GC)?

什么是垃圾回收?
·在任何计算设备中,垃圾回收是内存管理系统中重要的一部分。它的主旨是试图回收或者释放被物体占有但不再被程序利用的内存资源。
·它是一个高效自动的系统,试着保证不再需要的物体不会继续占有内存空间,并且保证高效和最优的内存使用。虽然它是一个自动系统,但是开发者们仍然可以控制它。
·通常,在处理能力允许的情况下,GC就会执行,以保证某些物体不会再被使用。

所以,这东西在Unity的foreach 循环里有什么用?
举个板栗,你就懂了
步骤1:在Unity中建立场景如下:
hierarchy.png
做一个画布,一个text作为显示,一个空GameObject重命名为GameObjectList.再创建一些新的空物体(约10~30个为宜)作为GameObjectList的子物体。
步骤2:创建一个脚本,命名为ForEachLoopTest.cs 我喜欢用C#,你也可以用Javascript:
[C#] 纯文本查看 复制代码
public class ForEachLoopTest : MonoBehaviour
{ 

    #region PUBLIC_DECLARATIONS

    public List<GameObject> emptyGameObjects;
    public Text indicatorText;

    #endregion


    #region UNITY_CALLBACKS


    void Update()
    {

        if (Input.GetKeyDown(KeyCode.Space))
        {
            indicatorText.text = "EXECUTION ON";
        }

        if (Input.GetKeyUp(KeyCode.Space))
        {
            indicatorText.text = "HOLD SPACE TO TURN ON EXECUTION";
        }
        if (Input.GetKey(KeyCode.Space))
        {
            UpdateTextValue();
        }
    }

    #endregion

    #region PUBLIC_METHODS

    public void UpdateTextValue()
    {
       
        foreach (var item in emptyGameObjects)
        {
            // PROCESS ITEMS IN LIST
        }
//        for (int i = 0; i < emptyGameObjects .Count; i++)
//        {
        // PROCESS ITEMS IN LIST
//        }
    }

    #endregion
}
注意:我已经注释掉了for循环,仅仅保留了forEach循环。

步骤3赋值和测试
按以下步骤赋值和测试按一下步骤赋值和测试
·运行游戏
·打开Profiler窗口
·将脚本挂在GameObjectList上,将所有空的GameObject拖到emptyGameObjects 列表
·点击空格键
有没有在Profiler发现什么?
profiler-forfach-loop.png

Profiler选中这一行,它显示了在空格键按下时,每一次Update分配了40B内存。现在,停止游戏回到代码中,把Foreach循环注释掉,把for循环打开。你会发现两者的遍历是一样的,现在,保存代码,运行游戏,重复上边的步骤。打开Profiler然后按下空格键。
有变化吗?


没有GC?6不6?在这个demo中,GC还有其他影响吗?
到底是怎样起作用的呢?
· 你可能要疯了“简直是浪费时间!在Profiler上并没有看到很大的变化啊!!”
·从这个例子来讲你是对的,但是想象一下,现在的情况是你需要执行不同的循环并且都超过上千次的遍历,每一次的循环都要耗费几个字节!

好吧,或许你是对的,但是这背后的原因是什么呢?
·你肯定会怀疑,只是一个循环而已!哪来的什么垃圾回收?
先看看语法:
[C#] 纯文本查看 复制代码
foreach (SomeType s in someList)
    s.DoSomething();

编译,编译器会将代码预处理为:
[C#] 纯文本查看 复制代码
using (SomeType.Enumerator enumerator = this.someList.GetEnumerator())
{
    while (enumerator.MoveNext())
    {
        SomeType s = (SomeType)enumerator.Current;
        s.DoSomething();
    }
}


WOW!很好,简单讲for-each会在每一次遍历中创建一个枚举对象,当遍历结束时,这些object都会消失。垃圾回收机会第一时间销毁这些不再使用的物体。因此导致GC,反过来导致延迟/故障在游戏更新,刺激玩家。

注意:
大量的GC取决于遍历的集合类型会有所不同。在我们的例子中是List集合,演示了约40B,但,如果用的是Dictinary或者其他集合可能会有不同的结果。
啊!我学会了!
我希望这是你读完这篇文章之后在你心里的感受!如果还没学会,可以在评论中向我提问。我也肯定会回复你。现在总结起来很简单,尽可能地避免在游戏中使用foreach。“每一个小小的优化都有助于长远的运行。”这就是这篇博客的全部内容!关注我们的博客站。我们会持续更新有关性能优化的博客。帮助你简化优化的艰难阶段。

这篇博客只是我们在Unity游戏优化方案系列中的一部分。如果你想学习怎样优化你的游戏,可以看这里
http://www.theappguruz.com/blog/unity-optimization-initiative

想获取游戏开发的idea?还等什么?现在就联系我们,让idea瞬间活起来。我司在印度被称为最好的 游戏开发公司,有之一。

原文作者:Rudra Gesota
原文连接:http://www.theappguruz.com/blog/foreach-loop-optimization
扫描下方二维码关注游戏蛮牛官方微信~每日都有精选干货与你分享哟~
file:///C:\Users\Administrator.AFAAW-704030720\AppData\Local\Temp\ksohtml\wpsCC0E.tmp.jpg
本文由蛮牛译馆倾情奉献,翻译:204有个大坑,如果问题请及时联系,除合作社区及合作媒体外,禁止转载。

profiler-simple-for-loop.png

回复

使用道具 举报

8常驻蛮牛
6013/10000
排名
243
昨日变化

0

主题

3053

帖子

6013

积分

Rank: 8Rank: 8

UID
3215
好友
0
蛮牛币
216
威望
0
注册时间
2013-9-4
在线时间
1332 小时
最后登录
2017-11-22
发表于 2017-5-18 16:59:52 | 显示全部楼层
的的的顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶

回复 支持 反对

使用道具 举报

5熟悉之中
802/1000
排名
2447
昨日变化
4

1

主题

12

帖子

802

积分

Rank: 5Rank: 5

UID
104427
好友
0
蛮牛币
2312
威望
0
注册时间
2015-5-30
在线时间
319 小时
最后登录
2017-11-23
发表于 2017-5-18 17:15:46 | 显示全部楼层
分析的挺好的

回复

使用道具 举报

4四处流浪
394/500
排名
9442
昨日变化
10

0

主题

216

帖子

394

积分

Rank: 4

UID
146677
好友
7
蛮牛币
1961
威望
0
注册时间
2016-4-25
在线时间
91 小时
最后登录
2017-11-22
QQ
发表于 2017-5-18 20:56:15 | 显示全部楼层
好东西,以前知道for比foreach性能高出很多,但是没有这么深入,谢谢作者的分析,受教了
[发帖际遇]: 一个袋子砸在了 LiuBen 头上,LiuBen 赚了 1 蛮牛币. 幸运榜 / 衰神榜

回复 支持 反对

使用道具 举报

5熟悉之中
750/1000
排名
2589
昨日变化
3

4

主题

78

帖子

750

积分

Rank: 5Rank: 5

UID
127539
好友
0
蛮牛币
3464
威望
0
注册时间
2015-11-1
在线时间
222 小时
最后登录
2017-11-8
QQ
发表于 2017-5-19 09:06:21 | 显示全部楼层
一看标题以为有什么好的解决方案
[发帖际遇]: iaming 发帖时在路边捡到 2 蛮牛币,偷偷放进了口袋. 幸运榜 / 衰神榜

回复 支持 反对

使用道具 举报

3偶尔光临
231/300
排名
10100
昨日变化
13

0

主题

90

帖子

231

积分

Rank: 3Rank: 3Rank: 3

UID
137397
好友
0
蛮牛币
9
威望
0
注册时间
2016-2-24
在线时间
63 小时
最后登录
2017-11-21
发表于 2017-5-19 10:05:44 | 显示全部楼层
尽可能地避免在游戏中使用foreach

回复 支持 反对

使用道具 举报

排名
23950
昨日变化
50

4

主题

25

帖子

78

积分

Rank: 2Rank: 2

UID
217789
好友
0
蛮牛币
95
威望
0
注册时间
2017-4-14
在线时间
37 小时
最后登录
2017-10-4
发表于 2017-5-19 14:49:48 | 显示全部楼层
for寻源很浪费性能吗?

回复 支持 反对

使用道具 举报

3偶尔光临
232/300
排名
10388
昨日变化
12

8

主题

38

帖子

232

积分

Rank: 3Rank: 3Rank: 3

UID
147783
好友
0
蛮牛币
145
威望
0
注册时间
2016-5-6
在线时间
113 小时
最后登录
2017-11-23
发表于 2017-5-19 17:00:27 | 显示全部楼层
不是讲优化吗,优化就是不用?假如我的一个字典表必须进行遍历查找怎么办

回复 支持 反对

使用道具 举报

5熟悉之中
661/1000
排名
4488
昨日变化
24

0

主题

252

帖子

661

积分

Rank: 5Rank: 5

UID
122160
好友
0
蛮牛币
1300
威望
0
注册时间
2015-9-10
在线时间
155 小时
最后登录
2017-11-23
发表于 2017-5-19 17:36:26 | 显示全部楼层
感谢分享

回复

使用道具 举报

5熟悉之中
626/1000
排名
3015
昨日变化
22

0

主题

89

帖子

626

积分

Rank: 5Rank: 5

UID
210517
好友
0
蛮牛币
2251
威望
0
注册时间
2017-3-7
在线时间
151 小时
最后登录
2017-11-22
发表于 2017-5-19 19:58:06 | 显示全部楼层
感谢分享,学习了

回复

使用道具 举报

4四处流浪
361/500
排名
6510
昨日变化
2

1

主题

68

帖子

361

积分

Rank: 4

UID
39740
好友
0
蛮牛币
572
威望
0
注册时间
2014-8-13
在线时间
136 小时
最后登录
2017-8-8
发表于 2017-5-20 11:58:15 | 显示全部楼层
最新5.6版好像已经修复这个性能损耗,我用5.61测试,foreach已经没有这部分GC了。

回复 支持 反对

使用道具 举报

排名
17698
昨日变化
37

1

主题

9

帖子

69

积分

Rank: 2Rank: 2

UID
193544
好友
0
蛮牛币
167
威望
0
注册时间
2016-12-18
在线时间
37 小时
最后登录
2017-10-27
发表于 2017-5-21 16:01:47 | 显示全部楼层
foreach不是在新版中已经优化了吗!这篇文章过时了。

回复 支持 反对

使用道具 举报

6蛮牛粉丝
1108/1500
排名
2059
昨日变化

1

主题

265

帖子

1108

积分

Rank: 6Rank: 6Rank: 6

UID
18721
好友
1
蛮牛币
1257
威望
0
注册时间
2014-3-24
在线时间
292 小时
最后登录
2017-11-15
发表于 2017-5-21 16:26:02 | 显示全部楼层
不错,来看看~

回复

使用道具 举报

6蛮牛粉丝
1411/1500
排名
1911
昨日变化
6

0

主题

485

帖子

1411

积分

Rank: 6Rank: 6Rank: 6

UID
164723
好友
0
蛮牛币
2837
威望
0
注册时间
2016-8-29
在线时间
346 小时
最后登录
2017-11-22
发表于 2017-5-22 09:27:45 | 显示全部楼层

回复

使用道具 举报

6蛮牛粉丝
1100/1500
排名
2223
昨日变化
4

8

主题

98

帖子

1100

积分

Rank: 6Rank: 6Rank: 6

UID
164216
好友
0
蛮牛币
3009
威望
0
注册时间
2016-8-25
在线时间
484 小时
最后登录
2017-11-1
发表于 2017-5-22 10:55:41 | 显示全部楼层
前来学习 谢谢楼主

回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册帐号

本版积分规则

关闭

站长推荐 上一条 /1 下一条

快速回复 返回顶部 返回列表