c# - 使用 IJobParallelFor 的 System.InedxOutOfRangeException

标签 c# unity-game-engine parallel-processing jobs

我尝试在 Unity 代码中使用 IJobParallelFor 来优化性能: 不幸的是我遇到了这样的错误:

System.IndexOutOfRangeException: Index {0} is out of restricted IJobParallelFor range [{1}...{2}] in ReadWriteBuffer.

我尝试使用

[NativeDisableParallelForRestriction]

[NativeDisableContainerSafetyRestriction]

但没有效果

[BurstCompile(CompileSynchronously = true)]

public struct DilationJob : IJobParallelFor
{
    
[ReadOnly]
public NativeArray<Color32> colorsArray;

public NativeArray<int> voxelToColor;
public int kernelSize;
public NativeArray<int> neighboursArray;
public int cubeNumber;


public void Execute(int index)
{   
    int dimx = 512;
    int  dimy = 512; 
    
    //int[] neighboursArray = new int[kernelSize * kernelSize * kernelSize];
    int listIndex = 0;
    
        for (int i = -1; i < kernelSize - 1; i++)
        {
            for (int j = -1; j < kernelSize - 1; j++)
            {
                for (int k = -1; k < kernelSize - 1; k++)
                {
                    int neigbourIndex = (i + 1) * (j + 1) * kernelSize + (j + 1) * kernelSize + (k + 1);

                    if (neigbourIndex < 0)
                    {
                        neigbourIndex = 0;
                    }

                    neighboursArray[neigbourIndex] =
                        index + k * dimx * dimy + j * dimx + i;

                    if (neighboursArray[neigbourIndex] < colorsArray.Length && neighboursArray[neigbourIndex] >= 0 &&
                        colorsArray[neighboursArray[neigbourIndex]].b == 255)
                    {
                        voxelToColor[listIndex] = index;
                        listIndex++;
                    }
                }
            }
        }
}

}

最佳答案

据我所知,此异常是由 IJobParallelFor 引起的同上说的是并行执行

Execute(int index) will be executed once for each index from 0 to the provided length. Each iteration must be independent from other iterations (The safety system enforces this rule for you). The indices have no guaranteed order and are executed on multiple cores in parallel.

Unity automatically splits the work into chunks of no less than the provided batchSize, and schedules an appropriate number of jobs based on the number of worker threads, the length of the array and the batch size.

这意味着假设您有一个长度为 10 的数组,并且您说批量大小可以达到 4 那么您可能最终会得到 3 个并行作业索引 [0, 1, 2, 3][4, 5, 6, 7][8, 9] 的 block 。由于这 3 个 block 中的每一个都可能位于不同的内核上,因此它们只能访问 NativeArray 的相应 block 。 (更多信息here)

可能发生的情况是,多个并行作业尝试访问并写入输出 NativeArrayvoxelToColorneighboursArray 的相同索引>。具体来说,如果不进行其余的计算,您肯定会尝试在每个并行作业中写入 voxelToColor[0] ,这既不允许,对我来说也没有多大意义。

在一次执行调用中,您只能写入给定的索引。

据我所知,该消息应该进一步阅读

ReadWriteBuffers are restricted to only read & write the element at the job index. You can use double buffering strategies to avoid race conditions due to reading & writing in parallel to the same elements from a job.

[ReadOnly] 标记的数组是异常(exception),因为只要您只读取,多个并行访问就不会损坏数据。


如果我理解正确的话,[NativeDisableContainerSafetyRestriction] 可以解决不同作业和主线程之间的竞争条件。

虽然您可能想要使用更多 [NativeDisableParallelForRestriction] 据我所知,它禁用了对数组索引的并行访问的安全限制。老实说,Unity API 在这些方面相当空闲。

举个小例子

public class Example : MonoBehaviour
{
    public Color32[] colors = new Color32[10];

    private void Awake()
    {
        var job = new DilationJob()
        {
            colorsArray = new NativeArray<Color32>(colors, Allocator.Persistent),
            voxelToColor = new NativeArray<int>(colors.Length, Allocator.Persistent)
        };

        var handle = job.Schedule(colors.Length, 4);

        handle.Complete();

        foreach (var i in job.voxelToColor)
        {
            Debug.Log(i);
        }

        job.colorsArray.Dispose();
        job.voxelToColor.Dispose();
    }
}

[BurstCompile(CompileSynchronously = true)]
public struct DilationJob : IJobParallelFor
{
    [ReadOnly] public NativeArray<Color32> colorsArray;

    [NativeDisableParallelForRestriction]
    public NativeArray<int> voxelToColor;

    public void Execute(int index)
    {
        voxelToColor[index] = colorsArray[index].a;

        if (index + 1 < colorsArray.Length - 1) voxelToColor[index + 1] = 0;
    }
}

不应引发任何异常。但是,如果您注释掉[NativeDisableParallelForRestriction],您将得到您所得到的异常。

关于c# - 使用 IJobParallelFor 的 System.InedxOutOfRangeException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70184462/

相关文章:

C# : How to pause the thread and continue when some event occur?

android - 可变屏幕分辨率 Sprite 不缩放统一

android - 应用程序在 FirebaseAuth.DefaultInstance 之后崩溃

c# - 为什么在C#中首次调用的并行处理要慢得多?

c# - 在不同的 View 模型之间共享PropertyChanged数据

c# - 引用 AssemblyInfo.cs 中的项目时发布预编译的 ASP.NET 失败

c# - 在 C# 中,如何从 C++/CLI 类中引用 typedef

android - 如何在 NDK-BUILD 中构建 arcore camera_utility 共享库?

concurrency - 与withPool并行

c# - 使用并行任务时x86和x64的数据类型有什么区别