UH4L10——值类型绑定

本章代码关键字

1
appDomain.RegisterValueTypeBinder()        //注册值类型与值类型绑定类的绑定,可以提高值类型计算效率

值类型绑定

通过上节课我们知道,CLR绑定其实就是把ILRuntime中用到的Unity相关方法
进行CLR重定向,让本来要使用反射去执行的一些逻辑变成直接执行,这样可以大大提升我们的性能
那么值类型绑定,其实就是把Unity当中的一些常用值类型方法进行CLR绑定,比如Vector2​、Vector3​、Quaternion​等
值类型绑定后,性能将得到大幅提升

值类型绑定,就是把Unity当中的一些常用值类型方法进行CLR绑定,它可以大幅提高在热更新工程中使用Unity中值类型对象的效率

如何进行值类型绑定

  1. 手写值类型绑定类(示例工程中提供了Vector2​、Vector3​、Quaternion​的,可以直接使用)

    注意:手写值类型绑定类必须了解ILRuntime原理,详见:UH4L18——基本原理UH4L21——重定向的书写规则

    image

  2. 注册值类型绑定

    appDomain.RegisterValueTypeBinder(typeof(值类型), new 绑定类());​,在CLR绑定脚本的InitILRuntime​中注册,

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    public class ILRuntimeCLRBinding
    {
    static void InitILRuntime(ILRuntime.Runtime.Enviorment.AppDomain domain)
    {
    //这里需要注册所有热更DLL中用到的跨域继承Adapter,否则无法正确抓取引用
    domain.RegisterCrossBindingAdaptor(new MonoBehaviourAdapter());
    domain.RegisterCrossBindingAdaptor(new CoroutineAdapter());
    domain.RegisterCrossBindingAdaptor(new TestClassBaseAdapter());
    //需要在这里注册我们自定义的一些需要跨域继承的类
    domain.RegisterCrossBindingAdaptor(new ILRuntimeAdapter.Lesson11_TestAdapter());

    domain.RegisterValueTypeBinder(typeof(Vector3), new Vector3Binder());
    domain.RegisterValueTypeBinder(typeof(Vector2), new Vector2Binder());
    domain.RegisterValueTypeBinder(typeof(Quaternion), new QuaternionBinder());
    }
    }

    在运行时,在appDomain​加载完热更新dll和pdb后也需要注册

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    //初始化ILRuntime相关的方法
    private unsafe void InitILRuntime()
    {
    //注册委托和委托转换器
    appDomain.DelegateManager.RegisterDelegateConvertor<MyUnityDel1>((action) =>
    {
    return new MyUnityDel1(() =>
    {
    ((System.Action)action)();
    });
    });
    appDomain.DelegateManager.RegisterMethodDelegate<int>();
    appDomain.DelegateManager.RegisterFunctionDelegate<int, int, int>();
    appDomain.DelegateManager.RegisterDelegateConvertor<MyUnityDel2>((func) =>
    {
    return new MyUnityDel2((i, j) =>
    {
    return ((System.Func<int, int, int>)func)(i, j);
    });
    });
    //注册跨域继承类
    appDomain.RegisterCrossBindingAdaptor(new ILRuntimeAdapter.Lesson11_TestAdapter());
    //注册值类型
    appDomain.RegisterValueTypeBinder(typeof(Vector3), new Vector3Binder());
    appDomain.RegisterValueTypeBinder(typeof(Vector2), new Vector2Binder());
    appDomain.RegisterValueTypeBinder(typeof(Quaternion), new QuaternionBinder());

    //CLR重定向内容,必须要写到CLR绑定之前!!!
    System.Type debugType = typeof(Debug);
    MethodInfo methodInfo = debugType.GetMethod("Log", new System.Type[] { typeof(object) });
    appDomain.RegisterCLRMethodRedirection(methodInfo, MyLog);

    //注册 CLR绑定相关信息
    ILRuntime.Runtime.Generated.CLRBindings.Initialize(appDomain);
    //初始化ILRuntime相关信息(目前只需要告诉ILRuntime主线程的线程ID,主要目的是能够在Unity的Profiler剖析器窗口中分析问题)
    appDomain.UnityMainThreadID = Thread.CurrentThread.ManagedThreadId;
    }

性能优化体现

在ILRuntime热更工程中使用Unity中值类型进行计算,不进行值类型绑定的效率较低,进行值类型绑定后性能将大幅提升

热更新测试值类型计算测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class ILRuntimeMain
{
public static void Main()
{
System.DateTime currentTime = System.DateTime.Now;
Vector3 v1 = new Vector3(123, 54, 567);
Vector3 v2 = new Vector3(342, 678, 123);
float dot = 0;
for (int i = 0; i < 1000000; i++)
{
dot += Vector3.Dot(v1, v2);
}
Vector2 v3 = new Vector2(12, 56);
Vector2 v4 = new Vector2(123123, 45345);
for (int i = 0; i < 1000000; i++)
{
dot += Vector2.Dot(v3, v4);
}
Debug.Log("值类型计算花费的时间:" + (System.DateTime.Now - currentTime).Milliseconds + "ms");
}
}

假设不进行值类型绑定的注册(可以删掉所有值类型CLR绑定相关内容再测试(实际上如果删除值类型相关绑定内容,相比值类型计算消耗的时间,加载dll文件时速度会大幅度拖慢,值类型计算量越大,加载时间越长,原因不明)),直接计算,耗时如下:

image

然后进行值类型绑定的注册,直接计算,耗时如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private unsafe void InitILRuntime()
{
//注册跨域继承类
appDomain.RegisterCrossBindingAdaptor(new ILRuntimeAdapter.Lesson11_TestAdapter());
//注册值类型
appDomain.RegisterValueTypeBinder(typeof(Vector3), new Vector3Binder());
appDomain.RegisterValueTypeBinder(typeof(Vector2), new Vector2Binder());
appDomain.RegisterValueTypeBinder(typeof(Quaternion), new QuaternionBinder());

//CLR重定向内容,必须要写到CLR绑定之前!!!
System.Type debugType = typeof(Debug);
MethodInfo methodInfo = debugType.GetMethod("Log", new System.Type[] { typeof(object) });
appDomain.RegisterCLRMethodRedirection(methodInfo, MyLog);

//注册 CLR绑定相关信息
ILRuntime.Runtime.Generated.CLRBindings.Initialize(appDomain);
//初始化ILRuntime相关信息(目前只需要告诉ILRuntime主线程的线程ID,主要目的是能够在Unity的Profiler剖析器窗口中分析问题)
appDomain.UnityMainThreadID = Thread.CurrentThread.ManagedThreadId;
}

image