您的位置:首页 > 移动开发 > Unity3D

Unity DOTS Jobs下调用引用类型

2019-06-07 08:59 155 查看
版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/buxingynjian225/article/details/91125619

Unity DOTS架构JobSystem的扩展

前言

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

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

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

Unity的异步方法

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

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();
}

/// <summary>
/// 回调函数.
/// </summary>
public Action Callback
{
get
{
return UnsafeUtility.ReadArrayElement<Action>(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);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐