背景:
在日常复制粘贴中,突然vs报错:EventSyetem没有此方法,我就想复制粘贴怎么出的错,原来因为vs2022 “ 强 大 ” 的补全,给我引用了Fantasy,使用了Fantasy中的EventSystem。原本删除引用就行了,但心血来潮,顺便看看Fantasy怎么处理事件系统的就点进去看了看,然后我就看到了Fantasy对于事件的加载过程。
/// <summary>
/// 在程序集加载时,遍历寻找并初始化事件。
/// </summary>
/// <param name="assemblyName">程序集名</param>
protected override void OnLoad(int assemblyName)
{
foreach (var type in AssemblyManager.ForEach(assemblyName, typeof(IEvent)))
{
var obj = (IEvent) Activator.CreateInstance(type);
if (obj != null)
{
var eventType = obj.EventType();
_events.Add(eventType, obj);
_assemblyEvents.Add(assemblyName, new EventInfo(eventType, obj));
}
}
foreach (var type in AssemblyManager.ForEach(assemblyName, typeof(IAsyncEvent)))
{
var obj = (IAsyncEvent) Activator.CreateInstance(type);
if (obj != null)
{
var eventType = obj.EventType();
_asyncEvents.Add(eventType, obj);
_assemblyAsyncEvents.Add(assemblyName, new EventInfo(eventType, obj));
}
}
}
fantasy中是先遍历程序集,找到所有泛型事件类,如何以类名为key存在一个字典中,调用时通过字典找到事件然后执行。看完就感觉到熟悉,储存泛型事件,用时调用,这不是我在writer序列化中干的事吗,不过但是因为不能代码织入,就只能在运行时实时储存,不过fantasy是用字典储存,通过key调用,而我是是用泛型类的静态变量储存。
至此,我就考虑,两者有何有优缺点
泛型类的缺点很明显,只能通过泛型的类型区分,也就是Type,而字典只要能计算哈希就行。
剩下就只有性能问题,简单写一个测试代码
public class Main : MonoBehaviour
{
Dictionary<Type, int> dic;
// Start is called before the first frame update
void Start()
{
//NetMgr.Instance.Init();
//LuaMgr.Init();
//UIManager.Instance.StackPanel<StartPanel>();
//UIManager.Instance.PreparePanel<TripleEliminationPanel>();
//TEManager.Instance.Init(5, 6, 10, (o) =>
//{
// foreach (var item in o)
// {
// Debug.Log(item);
// }
//});
//UIManager.Instance.ShowPanel<TripleEliminationPanel>();
//StartCoroutine(Text());
//ScanGameMgr.Instance.Init();
//ScanGameMgr.Instance.LoadMap(1000);
dic = new Dictionary<Type, int>();
dic[typeof(Key0)] = 0;
dic[typeof(Key1)] = 1;
dic[typeof(Key2)] = 2;
dic[typeof(Key3)] = 3;
dic[typeof(Key4)] = 4;
dic[typeof(Key5)] = 5;
dic[typeof(Key6)] = 6;
dic[typeof(Key7)] = 7;
dic[typeof(Key8)] = 8;
dic[typeof(Key9)] = 9;
}
private void Update()
{
if(Input.GetMouseButtonDown(0))
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (int i = 0; i < 100000; i++)
{
for (int j = 0; j < 10; j++)
{
dic[typeof(Key0)] = 0;
dic[typeof(Key1)] = 1;
dic[typeof(Key2)] = 2;
dic[typeof(Key3)] = 3;
dic[typeof(Key4)] = 4;
dic[typeof(Key5)] = 5;
dic[typeof(Key6)] = 6;
dic[typeof(Key7)] = 7;
dic[typeof(Key8)] = 8;
dic[typeof(Key9)] = 9;
}
}
stopwatch.Stop();
Debug.Log("DicThread execution time: " + stopwatch.ElapsedMilliseconds + " ms");
}
if (Input.GetMouseButtonDown(1))
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (int i = 0; i < 10000000; i++)
{
TextClass<Key0>.value = 0;
TextClass<Key1>.value = 0;
TextClass<Key2>.value = 0;
TextClass<Key3>.value = 0;
TextClass<Key4>.value = 0;
TextClass<Key5>.value = 0;
TextClass<Key6>.value = 0;
TextClass<Key7>.value = 0;
TextClass<Key8>.value = 0;
TextClass<Key9>.value = 0;
}
stopwatch.Stop();
Debug.Log("ClassThread execution time: " + stopwatch.ElapsedMilliseconds + " ms");
}
}
}
public class TextClass<T>
{
public static int value;
}
public interface IKey
{
}
public class Key0 : IKey
{
}
public class Key1 : IKey
{
}
public class Key2 : IKey
{
}
public class Key3 : IKey
{
}
public class Key4 : IKey
{
}
public class Key5 : IKey
{
}
public class Key6 : IKey
{
}
public class Key7 : IKey
{
}
public class Key8 : IKey
{
}
public class Key9 : IKey
{
}
使用鼠标左右键分开各执行10万次重复的十次不同键的赋值,使用Stopwatch测量线程耗时
测试结果:
各点击5次
增加泛型类数量,添加100倍到1000万次
if (Input.GetMouseButtonDown(1))
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (int i = 0; i < 10000000; i++)
{
TextClass<Key0>.value = 0;
TextClass<Key1>.value = 0;
TextClass<Key2>.value = 0;
TextClass<Key3>.value = 0;
TextClass<Key4>.value = 0;
TextClass<Key5>.value = 0;
TextClass<Key6>.value = 0;
TextClass<Key7>.value = 0;
TextClass<Key8>.value = 0;
TextClass<Key9>.value = 0;
}
stopwatch.Stop();
Debug.Log("ClassThread execution time: " + stopwatch.ElapsedMilliseconds + " ms");
}
加量测试结果:
初略估计泛型类效率为字典的600倍,性能差距极大。
结论:
综上,用泛型类来实现以Type为key的字典效果可以显著提升查询性能,但也只能查询赋值,并没有字典的其他功能,比如遍历等,而且是否有其他问题也不得而知,所以实际工程中是否使用还是视情况而定。