Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

NativeMultiHashMap<TKey, TValue>.ParallelWriter don't support concurents writes accross jobs

Discussion in 'Entity Component System' started by WAYNGames, Apr 11, 2020.

  1. WAYNGames

    WAYNGames

    Joined:
    Mar 16, 2019
    Posts:
    1,003
    Hello,

    I'm making a system where I have a job that loop through elements in a native queue and dispatch the element in a NativeMultiHashMap based on some attribute of the queue element.

    I expected using the NativeMultiHashMap.ParallelWriter to be able to schedule each job in parallel but it seems taht container only support concurent writes within the same job, not accross job.

    Code (CSharp):
    1.             NativeArray<JobHandle> MapperJobHanldes = new NativeArray<JobHandle>(CommandsQueues.Count, Allocator.Temp);
    2.             for (int i = 0; i < CommandsQueues.Count; i++)
    3.             {
    4.                 MapperJobHanldes[i] = new MapCommands()
    5.                 {
    6.                     CommandsMap = CommandsMap.AsParallelWriter(),
    7.                     CommandsQueue = CommandsQueues[i]
    8.                 }.Schedule(AfterResize);
    9.             }
    10.             MapperJobHanldes.Dispose();
    When a schedules the jobs squencially, it works fine.

    Code (CSharp):
    1.            JobHandle AfterMap = AfterResize;
    2.             for (int i = 0; i < CommandsQueues.Count; i++)
    3.             {
    4.                 AfterMap = new MapCommands()
    5.                 {
    6.                     CommandsMap = CommandsMap.AsParallelWriter(),
    7.                     CommandsQueue = CommandsQueues[i]
    8.                 }.Schedule(AfterMap);
    9.             }
    Is there a way to work around that ? Or the fact that each job could potentially write to the same key of the map at the same time is not handled by the ParallelWriter ?
     
  2. Lieene-Guo

    Lieene-Guo

    Joined:
    Aug 20, 2013
    Posts:
    547
    Try use the same ParallelWriter, instead of making new ones each time you Schedule a new job.
    Code (CSharp):
    1.             NativeArray<JobHandle> MapperJobHanldes = new NativeArray<JobHandle>(CommandsQueues.Count, Allocator.Temp);
    2.             var ParallelWriter = CommandsMap.AsParallelWriter();
    3.             for (int i = 0; i < CommandsQueues.Count; i++)
    4.             {
    5.                 MapperJobHanldes[i] = new MapCommands()
    6.                 {
    7.                     CommandsMap = ParallelWriter,
    8.                     CommandsQueue = CommandsQueues[i]
    9.                 }.Schedule(AfterResize);
    10.             }
    11.             MapperJobHanldes.Dispose();
    ParallelWrite from different job is Okay. It's just By calling AsParallelWriter from NativeMultiHashMap you are creating multiple safetyHandle to the same container.
    If it is still not working consider use UnsafeHashMap.
     
    Last edited: Apr 11, 2020
  3. WAYNGames

    WAYNGames

    Joined:
    Mar 16, 2019
    Posts:
    1,003
    Thanks, for your answer.
    Did not work with NativeMultiHashMap , had to use UnsafeMultiHashMap.
     
  4. Lieene-Guo

    Lieene-Guo

    Joined:
    Aug 20, 2013
    Posts:
    547
    For you job add this [Unity.Collections.LowLevel.Unsafe.NativeDisableContainerSafetyRestriction]
    to your ParallelWriter
     
    WAYNGames likes this.
  5. WAYNGames

    WAYNGames

    Joined:
    Mar 16, 2019
    Posts:
    1,003
    Works too :D

    The job
    Code (CSharp):
    1.  [BurstCompile]
    2.         struct MapCommands : IJob
    3.         {
    4.        
    5.             public NativeQueue<COMMAND> CommandsQueue;
    6.  
    7.             [WriteOnly]
    8.             [NativeDisableContainerSafetyRestriction]
    9.             public NativeMultiHashMap<ulong, COMMAND>.ParallelWriter CommandsMap;
    10.  
    11.             public void Execute()
    12.             {
    13.                 COMMAND command;
    14.                 while (CommandsQueue.TryDequeue(out command))
    15.                 {
    16.                     CommandsMap.Add(command.RegistryReference.TypeId, command);
    17.                 }
    18.  
    19.             }
    20.         }

    The scheduling

    Code (CSharp):
    1.   NativeArray<JobHandle> MapperJobHanldes = new NativeArray<JobHandle>(CommandsQueues.Count, Allocator.TempJob);
    2.             var CommandsMapParallelWriter = CommandsMap.AsParallelWriter();
    3.          
    4.             for (int i = 0; i < CommandsQueues.Count; i++)
    5.             {
    6.                 MapperJobHanldes[i] = new MapCommands()
    7.                 {
    8.                     CommandsMap = CommandsMapParallelWriter,
    9.                     CommandsQueue = CommandsQueues[i]
    10.                 }.Schedule(JobHandle);
    11.             }
     
  6. joshrs926

    joshrs926

    Joined:
    Jan 31, 2021
    Posts:
    116
    I had this same problem and I believe the solution is that the ParallelWriter versions of Native Containers are supposed to be used with IJobFor, not IJob. That's what solved it for me.