为什么 NativeArray 需要从 Unity 的 Job System 获取 return 值?

Why is NativeArray needed to obtain return values from Unity's Job System?

使用下面的代码块作为参考,单个更新提供以下结果:

intReturn = 0

inputArrayReturn = 1

internalArrayReturn = 1

这里唯一对我有意义的值是 internalArrayReturn

为什么 intReturn 不等于 1? 是什么导致了 stuct 的值没有改变,即使在执行期间它应该添加 1它?如果这只是 NativeArray 和 int 之间的根本区别,有人可以解释一下或给我指出一个可以帮助我更好地理解这一点的参考吗?

另外,为什么inputArrayReturn不等于0? NativeArray是一个结构,所以它不应该被视为值的副本而不是在 testArray = testArrayResults 行执行时引用?如果是这种情况,那么 inputArrayReturn 将保持等于 0 而不是更新为包含在 testJob.testArray.

中的相同值
using UnityEngine;
using Unity.Jobs;
using Unity.Collections;

public class ParallelTesting : MonoBehaviour
{
    void Update()
    {
        NativeArray<int> testArrayResults = new NativeArray<int>(1, Allocator.TempJob);

        TestJob testJob = new TestJob
        {
            testInt = 0,
            testArray = testArrayResults
        };

        JobHandle testJobHandle = testJob.Schedule();
        testJobHandle.Complete();

        int intReturn = testJob.testInt;
        int inputArrayReturn = testArrayResults[0];
        int internalArrayReturn = testJob.testArray[0];

        testArrayResults.Dispose();
    }

    public struct TestJob : IJob
    {
        public int testInt;
        public NativeArray<int> testArray;

        public void Execute()
        {
            testInt += 1;
            testArray[0] = testInt;
        }
    }
}

没有专家,但我会说 NativeArray 是专门为线程保存而设计的,基本上是 Unity 主线程和作业之间的共享内存 system/runner。

是的,NativeArray 是一个结构 ,但 事实上,如果你看一下 source code,它基本上只是一个包含指向实际结构的指针的包装器内存中的本机缓冲区。

    public unsafe struct NativeArray<T> : IDisposable, IEnumerable<T>, IEquatable<NativeArray<T>> where T : struct
    {
        [NativeDisableUnsafePtrRestriction]
        internal void*                    m_Buffer;
        internal int                      m_Length;

        internal int                      m_MinIndex;
        internal int                      m_MaxIndex;
        
        ...

这就是为什么两者

int inputArrayReturn = testArrayResults[0];
int internalArrayReturn = testJob.testArray[0];
  

通过相同的指针访问相同的外部存储器,因此 return 相同且正确的值。

然而,“正常”int 不一定是线程安全的,因为它没有分配外部内存(请参阅 Heap and Stack)并且您的 Unity 主线程不知道作业在内部发生了变化它在不同 thread/core.

上时的价值

Why doesn't intReturn equal 1?

因为 Unity.Jobs 使用在托管内存外部分配的专用内存块(本机容器、Unity.Collections、指针)和 testInt,虽然为工作线程编组,但未分配到外部任何地方堆叠.


Also, why doesn't inputArrayReturn equal 0?

因为 testArrayResultstestJob.testArray 都是同一个指针的副本,所以它们都引用发生在 new NativeArray<int>(1, Allocator.TempJob) 的相同分配。


Why is NativeArray needed to obtain return values from Unity's Job System?

这只是线程安全问题的一个很好的标准化解决方案,因为围绕这些容器的工具会警告您所有依赖关系、竞争条件等方式。

注意:您可以使用具有 [NativeDisableUnsafePtrRestriction] 属性的指针。但坚持使用本机容器更安全。