Search Unity

  1. Unity 2019.1 is now released.
    Dismiss Notice

Create Entities In Other Worker Threads Failed

Discussion in 'Entity Component System and C# Job system' started by YakShaver_dc, Apr 15, 2019.

  1. YakShaver_dc

    YakShaver_dc

    Joined:
    Mar 27, 2019
    Posts:
    9
    I try to create entities in other worker thread, not in main thread. I use 'EntityCommandBuffer' and encounter the error '
    NullReferenceException: Object reference not set to an instance of an object
    Unity.Entities.BarrierSystem.CreateCommandBuffer () (at Library/PackageCache/com.unity.entities@0.0.12-preview.24/Unity.Entities/ComponentSystem.cs:713). '
    my codes here:
    my barrier system
    Code (CSharp):
    1.  
    2. public class MyBarrier : BarrierSystem { }
    3.  
    job for creating entity
    Code (CSharp):
    1.  
    2. [BurstCompile]
    3. struct SpawnECS : IJobParallelFor
    4. {
    5.     public EntityCommandBuffer commandBuffer;
    6.     public EntityArchetype archetype;
    7.     public NativeArray<Entity> entities;
    8.     public void Execute(int index)
    9.     {
    10.         entities[index] = commandBuffer.CreateEntity(archetype);
    11.     }
    12. }
    13.  
    and in main thread
    Code (CSharp):
    1.  
    2. MyBarrier myBarrier = new MyBarrier();
    3. public void Spawn()
    4. {
    5.     NativeArray<Entity> entities = new NativeArray<Entity>(100, Allocator.Temp);
    6.     EntityCommandBuffer commandBuffer = myBarrier.CreateCommandBuffer();
    7.     SpawnECS job = new SpawnECS
    8.     {
    9.         commandBuffer = commandBuffer,
    10.         archetype = enemyParallelArchetype,
    11.         entities = entities
    12.     };
    13.     JobHandle handle = job.Schedule(entities.Length, 1);
    14.     handle.Complete();
    15.     entities.Dispose();
    16. }
    17.  
    Please help me to figure out the problem. Probably I use 'EntityCommandBuffer' in a wrong way, I will be appreciated to any example about creating entities by jobs.

    More information:
    Unity version 2018.3.7f1
    Entities version 0.0.12-preview 24
     
    Last edited: Apr 15, 2019
  2. Spy-Shifty

    Spy-Shifty

    Joined:
    May 5, 2011
    Posts:
    494
    Try the following:
    Code (CSharp):
    1. MyBarrier myBarrier = World.Active.GetOrCreateSystem<MyBarrier>();
     
  3. Spy-Shifty

    Spy-Shifty

    Joined:
    May 5, 2011
    Posts:
    494
    Anyway why are you scheduling a job for spawning entities?

    Just use the batch API it's much faster:
    Code (CSharp):
    1.  
    2. public void Spawn()
    3. {
    4.     using(var entities = new NativeArray<Entity>(100, Allocator.Temp)) {
    5.          EntitiyManager.CreateEntity(enemyParallelArchetype, entities);
    6.     }
    7. }
    Don't use jobs for that!
     
  4. YakShaver_dc

    YakShaver_dc

    Joined:
    Mar 27, 2019
    Posts:
    9
    Thank you for your answer.
    Since all these entities are created in main thread, there will be frame drop, and I think if I create entites parallelly will avoid the issue. Am I on the right track?
     
    Last edited: Apr 15, 2019
  5. YakShaver_dc

    YakShaver_dc

    Joined:
    Mar 27, 2019
    Posts:
    9
    I had to initialize NativeArray by Allocator.TempJob, and it works, but burst compiler raises an exception.
    Unexpected exception Burst.Compiler.IL.CompilerException: Unexpected exception ---> Burst.Compiler.IL.CompilerException: Error while processing function `Unity.Entities.World Unity.Entities.World::get_Active()` ---> Burst.Compiler.IL.CompilerException: Unexpected error while processing `IL_0000: ldsfld Unity.Entities.World
    Unity.Entities.World::<Active>k__BackingField` at
    C:\Projects\ecs_test\Library\PackageCache\com.unity.entities@0.0.12-preview.24\Unity.Entities\Injection\World.cs(42,38) ---> System.NotSupportedException: The managed class type `Unity.Entities.World` is not supported. Loading from a static field `Unity.Entities.World Unity.Entities.World::<Active>k__BackingField` is not supported by burst
    at Burst.Compiler.IL.ILVisitor.NotSupported (Burst.Compiler.IL.Syntax.ILInstruction inst)

    maybe the same issue in this thread https://forum.unity.com/threads/anyone-got-burst-working-with-entitycommandbuffer.543789/
     
    Last edited: Apr 15, 2019
  6. FrankvHoof

    FrankvHoof

    Joined:
    Nov 3, 2014
    Posts:
    82
    No. Entities will ALWAYS be created on the main thread.
    Unless you're doing a lot of setup/init in your thread, there should be no difference (using a cmdbuffer will have a bit more overhead).
    CommandBuffers just schedule the work to be ran at a later time. The work itself (spawning, add/remove component, etc.) is still done on the main thread.
     
  7. FrankvHoof

    FrankvHoof

    Joined:
    Nov 3, 2014
    Posts:
    82
    Doe the GetSystem() in your system, not your job (you'll probably want to put it in OnCreateManager())
    Then, create the commandbuffer (make it concurrent if you need to), and pass that to your job.
    Don't forget to add the JobHandle for your job to the producer of the commandbuffer using bufferSystem.AddJobHandleForProducer (this takes the handle that's returned when scheduling your job)), and, if you can, use Unity's built-in CommandBufferSystems to prevent having to run a seperate buffersystem.
     
  8. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    1,057
    ECB creates entities on main thread too, but later.

    Not always.
    ExclusiveEntityTransaction in different world gives you opportunity to create entities in other world on one of worker threads, without main thread block. Moving this entities to main thread world by MoveEntitiesFrom block main thread (but it's other strory) but creation process itself on other thread in this EET case.
     
  9. YakShaver_dc

    YakShaver_dc

    Joined:
    Mar 27, 2019
    Posts:
    9
    Glad to know these, thank you, eizenhorn and FrankvHoof.