Unity DOTS Jobs下调用引用类型

Unity DOTS架构JobSystem的扩展

  • 前言
    • Unity的异步方法
    • Unity异步方法优势对比:
    • JobAction 实现

前言

Unity 官方计划 未来 会全面转入ECS+ Jobs +Burst 的DOTS架构. 但事实上这三个子系统是相互彼此独立的.换句话说,你可以单独选择使用某部分,而不必全部使用.在这里将探讨Job系统背后的细节.官方文档 把Jobs系统描述 为一个只能使用值类型的多线程系统.背后又是如何实现的呢?用一句话归纳说:Jobs系统其实是用C++实现的一个线程池.因为是非委托的实现.所以C#的对象锁的概念将不再可用.这意味着全部的引用类型 在多线程同时读写的时候会因为相互干扰而破坏数据.Unity官方为回避这个问题,仅使用值类型,而抛弃了全部引用类型. 值类型因为只是源数据的一个副本,对其做的任何修改 是不会修改源数据的,利用这个特性,在空间上可以完美隔离多线程的资源竞争,并且提升性能.Jobs为仅支持值类型可用,特别实现一套类型安全检查,旨在排除引用类型的错误使用.但事实上如果在多线程执行期间只做引用类型读写操作的话并非会构成任何问题. 于是有人想过使用静态成员变量绕过该安全检查,以期望在Jobs系统中调用引用类型.

我使用UnsafeUtility的方法编写JobAction值类型包装Action委托,可以绕开这个安全检查达到同样的目的,这是Jobs系统可以执行引用类型上下文的第二条有效方法,并且更加灵活.(注意,使用完毕之后需要Dispose是否资源)

以下列出几种异步方法表格用于对比相互优势取舍:

Unity的异步方法

C#代码端
Coroutine协程
迭代器方法
单线程上下文包装
Thead 手动构建
多线程指令
Task/Async/Await
Task委托线程池
IJob/IJobParallelFor
Jobs非委托线程池

Unity异步方法优势对比:

Coroutine协程 Thread线程 Task多线程 Jobs多线程 Jobs多线程 中使用JobAction
主线程仅切换上下文,不使用多线程 手动创建销毁线程,切换效率低.拥有对象锁,可能因资源竞争等待而降低效率 线程池调度多线程,切换效率高,拥有对象锁,可能因资源竞争等待而降低效率 非托管代码线程池调度多线程,没有对象锁,无资源竞争等待,充分使用多线程,只能使用值类型数据, 非托管代码线程池调度多线程,没有对象锁,无资源竞争等待,充分使用多线程.可以使用引用类型和值类型,同时读写引用类型数据会相互干扰导致数据错误.

JobAction 实现

using Unity.Collections.LowLevel.Unsafe;
using System;
public unsafe struct VJobAction :IDisposable
{
   [NativeDisableUnsafePtrRestriction]
   private void* m_Ptr;
   private ulong m_Handle;

   public VJobAction(Action aCallback)
   {
       var aArr = new Action[] { aCallback };
       m_Ptr = UnsafeUtility.PinGCArrayAndGetDataAddress(aArr, out m_Handle);
   }

   public void Invoke()
   {
       Callback?.Invoke();
   }

   /// 
   /// 回调函数.
   /// 
   public Action Callback
   {
       get
       {
           return UnsafeUtility.ReadArrayElement(m_Ptr, 0);
       }
       set
       {
           Dispose();

           var aArr = new Action[] { value };
           m_Ptr = UnsafeUtility.PinGCArrayAndGetDataAddress(aArr, out m_Handle);
       }
   }

   public void Dispose()
   {
       if (m_Handle != 0)
       {
           UnsafeUtility.ReleaseGCObject(m_Handle);
           m_Ptr = (byte*)0;
           m_Handle = 0;
       }
   }

   public static implicit operator Action (VJobAction aCallback)
   {
       return aCallback.Callback;
   }

   public static explicit operator VJobAction( Action aCallback)
   {
       return new VJobAction(aCallback);
   }
}
  • https://github.com/ColinGao225/UnityStuff/blob/master/src/VJobAction.cs

你可能感兴趣的:(编程)