C# Job System中的安全性系统

https://docs.unity3d.com/Manual/JobSystemSafetySystem.html​docs.unity3d.com

资源竞争

当我们编写多线程代码时,经常会有产生资源竞争的风险。资源竞争会在一项操作的输出依赖于另一项它掌控之外的操作时发生。

资源竞争并不总是视为一个bug,但它却是不确定行为发生的原因之一。当资源竞争确实引发了一个bug时,因为是偶然发生的,因此很难找到问题发生的确切原因,你只能在偶然情况下才能重现这种问题。调试时问题可能就消失了,因为断点和日志可能改变单个进程的执行时机。因此资源竞争成为了编写多线程代码时最大的挑战。

安全性系统

为了让用户更容易地编写多线程代码,Unity中的C# Job System会检测所有潜在的资源竞争,从而避免用户遇到由此产生的bug

举例来说:如果C# Job System需要在主线程中发送一个数据的引用给一个Job,Job在写入对应数据的时候无法判断主线程是否也在同时操作该数据。这种情况下就会导致资源竞争。

C# Job System通过给每一个需要操作数据的Job一份数据的拷贝而不是主线程中数据的引用来避免这个问题。拷贝和原本的数据独立,从而排除了资源竞争。

C# Job System拷贝数据的方式表明了一个Job只能访问可以位块传输的数据类型(blitable data types)。这种数据类型在托管代码和原生代码之间进行传递的时候不需要类型转换。

C# Job System可以使用memcpy来拷贝可位块传输数据,并在Unity的托管部分和原生部分之间传递它们。它在安排job时使用memcpy将数据放入原生内存,并给予托管部分在job执行时访问这份拷贝数据的接口。查阅更多的信息,查看Scheduling jobs

NativeContainer

https://docs.unity3d.com/Manual/JobSystemNativeContainer.html​docs.unity3d.com

安全性系统中拷贝数据的缺点是单个job的计算结果是与外部隔离的。为了突破这个限制,我们需要把结果放在一种共享内存——NativeContainer中。

什么是NativeContainer?

NativeContainer是一种托管的数据类型,为原生内存提供一种相对安全的C#封装。它包括一个指向非托管分配内存的指针。当和Unity C# Job System一起使用时,一个NativeContainer使得一个Job可以访问和主线程共享的数据,而不是在一份拷贝数据上工作。

有什么可用的NativeContainer类型?

Unity使用一个叫做NativeArray的NativeContainer。你还可以通过一个NativeSlice来操作一个NativeArray,从而获得从某个特定位置开始确定长度的NativeArray子集。

注意:Entity Component System(ECS)包扩展了Unity.Collections命名空间,包括了其他类型的NativeArray:

  • NativeList - 一个可变长的NativeArray
  • NativeHashMap - 键值对
  • NativeMultiHashMap - 每个Key可以对应多个值
  • NativeQueue - 一个先进先出(FIFO)队列

NativeContainer和其安全性系统

安全性系统是所有NativeContainer类型的组成部分。它会追踪所有关于任何NaiveContainer的读写。

注意:所有关于NativeContainer类型的安全性检查(包括下标边界检查,内存释放检查和资源竞争检查),只在Unity Editor和Play Mode中生效。(译者:即只在编辑器环境中进行检查)

安全性系统是由DisposeSentinelAtomicSafetyHandle组成的。DisposeSentinel检测内存泄漏同时在你没有正确释放内存的时候给你一个错误信息。但内存泄漏的错误只有在泄露发生很久之后才会触发。

使用AtomicSafetyHandle在代码中进行NativeContainer所有权的转移。举例来说,如果两个已经安排的jobs向同一个NativeArray写入数据,安全性系统会抛出一个异常,带有明确的错误信息关于为什么以及如何解决这个问题。安全性系统会在你安排一个违规的job后抛出一个异常。

在这种情况下,你可以在安排job的时候添加一个依赖。第一个job可以写入到NativeContainer,一旦它执行完毕,下一个job可以安全地读取和写入同一个NativeContainer。读取和写入的限制同样影响在访问主线程中的数据时生效。安全性系统允许多个jobs并行的读取同一份数据。

通常来说,当一个job有NativeContainer的访问权限时,它同时拥有读取和写入的权限。这种配置会使性能变差。一个C# Job System不允许你在有job正在对一个NativeContainer进行读写的时候,安排另一个job对该NaiveContainer拥有写入权限。

如果某个job不需要向某个NativeContainer写入,可以将该NativeContainer加上[ReadOnly]属性,像这样

[ReadOnly]
public NativeArray<int> input;

在上面的例子中,你可以在其他jobs拥有该NativeContainer只读权限的时候同时执行该job。

注意:这边没有针对从一个job中访问静态数据的保护。访问静态数据可以绕过所有的安全性系统并可能导致Unity奔溃。关于更多的信息,可以查看C# Job System建议和错误定位

NativeContainer分配器(Allocator)

当创建一个NativeContainer时,你必须指定你需要的内存分配类型。分配的类型由jobs运行的时间来决定。这种情况下你可以在每一种情况下使分配器达到可能的最好性能。

这里对于NativeContainer的内存分配有三个分配器类型。当你初始化你的NativeContainer时你需要指定一个合适的分配器。

  • Allocator.Temp是最快的分配类型。它适用于分配一个生命周期只有一帧或更短时间的操作。你不应当把一个分配器为Temp类型分配的NativeContainer传递给jobs使用。你同时需要在函数返回之前调用Dispose方法(例如MonoBehaviour.Update,或者其他从原生到托管代码的调用)
  • Allocator.TempJob是相比于Temp是一个较慢的分配类型但它比Persistent要快。这是一个生命周期为四帧的内存分配而且它是线程安全的。如果你在四帧之内没有调用Dispose,控制台会打印一个由原生代码生成的警告信息。绝大部分小jobs使用这种类型的NativeContainer分配器。
  • Allocator.Persistent是最慢的分配类型但,它可以持续存在到你需要的时间,如果必要的话可以贯穿应用程序的整个生命周期。它是直接调用malloc的一个封装。长时间的jos可以使用这种分配类型。当性能比较紧张的时候你不应当使用Persistent

使用示例:

NativeArray<float> result = new NativeArray<float>(1, Allocator.TempJob);

注意:上例中的1表明了NativeArray的长度。在这个例子中,它只有一个数组元素(因为它只在result中存储了一块数据)。

Unity C# Job System介绍(二) 安全性系统和NativeContainer相关推荐

  1. Unity C# Job System介绍(四) 并行化Job和故障排除(完结)

    并行化job ParallelFor jobs​docs.unity3d.com 当调度Jobs时,只能有一个job来进行一项任务.在游戏中,非常常见的情况是在一个庞大数量的对象上执行一个相同的操作. ...

  2. Unity C# Job System介绍(一) Job System总览和多线程

    C# Job System 总览 Unity的C# Job System使用户可以编写与Unity其他部件交互的多线程代码,同时让编写正确的代码变得更容易. 编写多线程代码可以提供更好的性能表现.这包 ...

  3. Unity C# Job System介绍(三) Job的创建和调度

    创建Jobs Unity - Manual: Creating jobs​docs.unity3d.com 为了在Unity中创建一个job你需要实现IJOb接口.IJob允许你调度一个job,和其他 ...

  4. 【嵌入式Linux】嵌入式Linux驱动开发基础知识之Pinctrl子系统和GPIO子系统的使用

    文章目录 前言 1.Pinctrl子系统 1.1.为什么有Pinctrl子系统 1.2.重要的概念 1.3.代码中怎么引用pinctrl 2.GPIO子系统 2.1.为什么有GPIO子系统 2.2.在 ...

  5. win10共享计算机win7,Win7系统和win10系统设置共享打印机的方法

    打印机是办公室经常会用到的打印设备,而有时候办公室只有一台打印机,那么为了方便使用我们就可以通过局域网来共享打印机,那么如果局域网中有win7系统和win10系统的话,要怎么设置共享打印机呢?接下来给 ...

  6. 详解Unity中的粒子系统Particle System (十二 | 终)

    前言 终于来到了最后一篇,粒子系统宣告终结!这十来篇博客删删改改写了半个多月,真是离谱.今天该讲案例与粒子系统的应用,那么我们就进入正题吧! 目录 前言 本系列提要 一.如何做出效果 二.案例演示 1 ...

  7. Unity中的动画系统和Timeline——笔记

    前言: 最近开始跟着SIKI学院系统学习Unity,这篇文章就是Unity中的动画系统和Timeline的笔记 动画 动画的录制和动画曲线的编辑 以前我都是在动画中一步一步来做动画,从来不知道还有这个 ...

  8. Android A/B System OTA分析(三)主系统和bootloader的通信

    Android从7.0开始引入新的OTA升级方式,A/B System Updates,这里将其叫做A/B系统,涉及的内容较多,分多篇对A/B系统的各个方面进行分析.本文为第三篇,主系统和bootlo ...

  9. Lucene.Net 2.3.1开发介绍 —— 二、分词(一)

    原文:Lucene.Net 2.3.1开发介绍 -- 二.分词(一) Lucene.Net中,分词是核心库之一,当然,也可以将它独立出来.目前Lucene.Net的分词库很不完善,实际应用价值不高.唯 ...

最新文章

  1. css transform旋转属性
  2. Wait--查看等待
  3. 高效CNN推理库、多款AlphaGo实现…你们喜欢的Github项目精选又来了!
  4. python直接使用pyc_Pyc和pyo是怎样一种存在?
  5. HTML5学习笔记简明版(4):新元素之video,audio,meter,datalist,keygen,output
  6. yii_wiki_145_yii-cjuidialog-for-create-new-model (通过CJuiDialog来创建新的Model)
  7. Gartner发布2022年七大安全和风险管理趋势
  8. AI学习笔记(九)从零开始训练神经网络、深度学习开源框架
  9. java string查找_Java lastIndexOf() 方法
  10. 2019年架构软考论文押题(一)
  11. linux虚拟机中如何复制粘贴内容到主机
  12. ftp服务器无法上传文件,ftp无法上传文件的原因
  13. 平均增长率不用计算机,官方数据:平均增长率计算公式如何使用excel计算平均增长率...
  14. Java学习笔记(13)-构造方法
  15. 泪目了,一位轮椅上的清华博士师兄
  16. 【天光学术】文学理论论文:符号学理论下文本互文性探究(节选)
  17. 1698无法登录mysql服务器_一,问题描述:MysqlERROR1698(28000)解决,新装了mysql-server-5.7,登录为这一问题,普通用户不能进mysql,只有root用...
  18. 【Java】IO流 - 节点流和处理流【Buffered】
  19. EMUI10开启公测!华为P30系列率先尝鲜,详细升级教程奉上
  20. 美通企业日报 | 特步签约林书豪进军篮球领域;中兴和中国移动直播中国首个5G运动会...

热门文章

  1. 安装mysql的过程可以中断吗_安装 mysql 遇到的坑(附 mysql 安装过程)
  2. 5 拦截器拦截请求路由_手写简易版axios拦截器,实现微信小程序wx.request的封装与拦截...
  3. linux 将img写入硬盘,如何使用Etcher轻松将.img写入Mac上的SD卡
  4. 没有run窗口_学会了面向对象,还怕没有对象?
  5. 常用的数据结构_三分钟了解区块链常用数据结构「默克尔树」
  6. phpexcel 导出循环增加列数_基于.NetCore3.1搭建项目系列 —— 使用Swagger导出文档 (补充篇)...
  7. 数学--数论--(逆元)扩展欧几里求解+证明
  8. linux下程序如何实现单实例运行
  9. [机器学习] --- Getting Started With MachineLearning
  10. 关于keil环境的 三个红点(备忘)