Search Unity

Cant access to elements of Concurrents native containers

Discussion in 'Entity Component System' started by SirMazius, Apr 24, 2018.

  1. SirMazius

    SirMazius

    Joined:
    Oct 26, 2016
    Posts:
    11
    Im experimenting with concurrent versions of Hash & MultiHash Maps but im not been able to recover data from them, is there a specific way to do this?

    maybe something like
    TryGetValue(key, out item)?


    Thanks by the way, and sorry for my ignorance
     
  2. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,685
    If you inspect NativeHashMap and NativeMultiHashMap you’ll see - only adding. Read more about concurent native containers in ECS docs.
     
  3. SirMazius

    SirMazius

    Joined:
    Oct 26, 2016
    Posts:
    11
    I did it but couldn't found nothing about concurrent containers in apecific.
    Could you give me the link?
     
  4. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,685
  5. SirMazius

    SirMazius

    Joined:
    Oct 26, 2016
    Posts:
    11
  6. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,685
    Keywords - "deterministic write access". If you look at the example of NativeCounter (or inspect any other Concurent struct in NativeHashMap, NativeQueue, etc), you'll see that Concurent struct has [NativeContainerIsAtomicWriteOnly] attribute, that's mean you can't acces read data from Concurent struct.
     
  7. SirMazius

    SirMazius

    Joined:
    Oct 26, 2016
    Posts:
    11
    So how do you use data stored in that containers if you cant access directly?
     
  8. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,685
    For write i'm using one job, for read - other (Without Concurrent extension)
     
  9. futurlab_peterh

    futurlab_peterh

    Joined:
    Jan 23, 2018
    Posts:
    38
    The way I solved this was by using a NativeMultiHashMap:

    Code (CSharp):
    1.  
    2. private void DoStuff()
    3. {
    4.     var myCollection = new NativeMultiHashMap< int, MyData >( 123, Allocator.Temp );
    5.  
    6.     // This job will use only key=0, like this:
    7.     // CollectionToWriteTo.Add( 0, new MyData() );
    8.     var myJob = new SomeJob
    9.     {
    10.         CollectionToWriteTo = myCollection.ToConcurrent(),
    11.     };
    12.  
    13.     var jobHandle = myJob.Schedule( this, inputDeps );
    14.     jobHandle.Complete();
    15.  
    16.     foreach ( var data in myCollection.GetEnumerator() )
    17.     {
    18.         Log( "Data changed: {0}", data );
    19.     }
    20.  
    21.     myCollection.Dispose();
    22. }
    23.  
    24.  
    25. // Extension method to ease enumerating a NativeMultiHashMap; assumes default(TKey) if no other key is passed as a parameter
    26. public static IEnumerable< TValue > GetEnumerator< TKey, TValue >( this NativeMultiHashMap< TKey, TValue > nativeMultiHashMap, TKey key = default( TKey ) )
    27.     where TKey : struct, IEquatable<TKey>
    28.     where TValue : struct
    29. {
    30.     if ( nativeMultiHashMap.TryGetFirstValue( key, out var value, out var iterator ) )
    31.     {
    32.         yield return value;
    33.         while ( nativeMultiHashMap.TryGetNextValue( out value, ref iterator ) )
    34.         {
    35.             yield return value;
    36.         }
    37.     }
    38. }
    39.  
     
  10. Zooltan

    Zooltan

    Joined:
    Jun 14, 2013
    Posts:
    19
    You can also make a small job, where you put the results into a NativeArray.

    I do it with NativeQueue, where I use a single threaded job to iterate through it and extract all entries to a NativeArray, which I can then use concurrently in a different job. Even though it's a single thread, it's very fast.

    I'm not sure how you should iterate through the NativeMultiHashMap in a job though, as you will need to know all the keys in advance.


    (Here is my Queue -> NativeArray code if anyone would be interested)
    Code (CSharp):
    1. [BurstCompile]
    2.     public struct DequeueIntoArray<T> : IJob where T : struct
    3.     {
    4.         public int StartIndex;
    5.         public NativeQueue<T> InputQueue;
    6.         [WriteOnly] public NativeArray<T> OutputArray;
    7.  
    8.         public void Execute()
    9.         {
    10.             int queueCount = InputQueue.Count;
    11.  
    12.             for (int i = StartIndex; i < StartIndex + queueCount; i++)
    13.             {
    14.                 OutputArray[i] = InputQueue.Dequeue();
    15.             }
    16.         }
    17.     }
     
    futurlab_peterh likes this.
  11. futurlab_peterh

    futurlab_peterh

    Joined:
    Jan 23, 2018
    Posts:
    38

    Yeah that's why I write all values using the same key. I liked your solution, I'll give it a go soon!
     
  12. Zooltan

    Zooltan

    Joined:
    Jun 14, 2013
    Posts:
    19
    Ah, well if you don't use the actual Key-Value relation of the hashmap, and you just need to save something from a job that you can iterate over later, then using a concurrent NativeQueue is a much better way of doing it.
     
    futurlab_peterh likes this.