38.性能优化-CPU-脚本-数据结构选择
38.1 知识点
数据结构选择
数据结构选择是指在 Unity 脚本中用合适的数据结构来装载数据。常用的 List 和 Dictionary 各有优劣,应按场景选用。
List<T>:
- 查找时间复杂度
O(n)(按索引访问为O(1))。 - 存储结构连续,遍历时缓存友好。
Dictionary<TKey, TValue>:
- 查找时间复杂度
O(1)(按 key)。 - 存储结构不连续,依赖哈希表。
选择建议:
- 经常遍历、中间插入较少:用 List,顺序访问快、内存局部性好。
- 经常按键查找:用 Dictionary,避免线性查找。
示例:
using System.Collections.Generic;
// 需要频繁遍历、顺序处理时用 List
List<Enemy> enemyList = new List<Enemy>();
foreach (Enemy enemy in enemyList)
{
enemy.UpdateLogic();
}
// 需要按 ID 等键快速查找时用 Dictionary
Dictionary<int, Player> playerDictionary = new Dictionary<int, Player>();
if (playerDictionary.TryGetValue(playerId, out Player player))
{
player.ApplyDamage(amount);
}
更多数据结构选择
除 List 和 Dictionary 外,下列结构在特定场景下更合适。
HashSet<T>
- 时间复杂度:查找 / 添加 / 删除均为
O(1),内部为哈希表。 - 使用场景:只关心“是否存在”、不需要顺序、也不需要键值对,例如当前激活的敌人集合、已处理对象集合。
using System.Collections.Generic;
// 只关心“是否已包含”,不关心顺序
HashSet<GameObject> activeEnemySet = new HashSet<GameObject>();
activeEnemySet.Add(enemy);
if (activeEnemySet.Contains(enemy)) { }
activeEnemySet.Remove(enemy);
Queue<T>
- 时间复杂度:入队、出队
O(1)。 - 使用场景:按顺序处理(先进先出),例如对象池中存放可复用对象。
using System.Collections.Generic;
// 对象池:从队头取、用完后从队尾放回
Queue<GameObject> poolQueue = new Queue<GameObject>();
poolQueue.Enqueue(instance);
GameObject next = poolQueue.Dequeue();
Stack<T>
- 时间复杂度:入栈、出栈
O(1)。 - 使用场景:先进后出,例如行为回退、状态回溯。
using System.Collections.Generic;
// 状态/行为回退
Stack<GameState> stateStack = new Stack<GameState>();
stateStack.Push(currentState);
GameState previous = stateStack.Pop();
LinkedList<T>
- 时间复杂度:在已知节点处插入、删除
O(1),按值查找O(n)。内存不连续,缓存命中率低,不推荐频繁整体遍历。 - 使用场景:需要频繁在中间插入、删除,且不依赖整体遍历性能时。
using System.Collections.Generic;
// 频繁在中间插入/删除,且已有节点引用时
LinkedList<Node> nodeList = new LinkedList<Node>();
LinkedListNode<Node> node = nodeList.Find(target);
if (node != null)
nodeList.Remove(node);
SortedDictionary<TKey, TValue>、SortedList<TKey, TValue>
- 特点:按 Key 有序;插入、删除、查找
O(log n),比 Dictionary 慢,但顺序稳定。 - 使用场景:需要按 Key 顺序遍历键值对,例如按时间调度的事件。
using System.Collections.Generic;
// 按时间键顺序处理事件
SortedDictionary<float, Action> scheduledEvents = new SortedDictionary<float, Action>();
foreach (KeyValuePair<float, Action> pair in scheduledEvents)
{
if (pair.Key <= currentTime)
pair.Value?.Invoke();
}
ConcurrentDictionary、ConcurrentQueue 等
- 特点:线程安全,内部带锁。
- 使用场景:Unity 主线程逻辑中一般用不到,适合多线程工具层、后台线程与主线程之间共享集合时使用。
38.2 知识点代码
Lesson38_性能优化_CPU_脚本_数据结构选择.cs
using UnityEngine;
public class Lesson38_性能优化_CPU_脚本_数据结构选择 : MonoBehaviour
{
void Start()
{
#region 知识点一 数据结构选择
/* 在 Unity 中用合适的数据结构装载数据。
* List:查找 O(n),连续存储,适合常遍历、中间插入少。
* Dictionary:查找 O(1),不连续存储,适合常按键查找。*/
#endregion
#region 知识点二 更多数据结构选择
/* HashSet<T>:查找/添加/删除 O(1),只关心存在性、无顺序时用。
* Queue<T>:入队出队 O(1),先进先出,如对象池。
* Stack<T>:入栈出栈 O(1),先进后出,如状态回退。
* LinkedList<T>:中间插删 O(1)、查找 O(n),不连续内存,少用于频繁遍历。
* SortedDictionary/SortedList:按 Key 有序,操作 O(log n),适合按序遍历键值对。
* Concurrent*:线程安全,主线程逻辑一般不用,多线程工具层可用。*/
#endregion
}
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com