Search Unity

How to Disable Entities.ForEach Parallel Safety Check (two jobs writing to same component type)?

Discussion in 'Entity Component System' started by diesoftgames, Apr 21, 2020.

  1. diesoftgames

    diesoftgames

    Joined:
    Nov 27, 2018
    Posts:
    122
    Say I have for instance:

    Code (CSharp):
    1. var job1Handle = Entities
    2.     .WithAll<ExclusionTag>
    3.     .ForEach((ref WriteToData writeToData) =>
    4. {
    5.     // Some work
    6. }).Schedule(inputDeps);
    7.  
    8. var job2Handle = Entities
    9.     .WithNone<ExclusionTag>
    10.     .ForEach((ref WriteToData writeToData) =>
    11. {
    12.     // Some other work
    13. }).Schedule(inputDeps);
    14.  
    15. return JobHandle.CombineDependencies(job1Handle, job2Handle);
    Since the two jobs use the ExclusionTag component to xor the results of their queries, I know I won't try to write to the same components, but I get a safety check error when this system runs. I'm upgrading from a much earlier version of Unity.Entities that just didn't have this safety check I guess because this wasn't complaining. How can I tell it that it's okay for these to run parallel? (for now I'm just making job1Handle a dependency for job2 and returning job2Handle, but my understanding is that means this won't run parallel)
     
    Vaarz likes this.
  2. joepl

    joepl

    Unity Technologies

    Joined:
    Jul 6, 2017
    Posts:
    87
    I don't believe this is possible currently. We let you disable safety checks on captured variables, but not on the lambda parameters themselves. I think you would need to use an IJobChunk for this currently. I'll look into if we can provide a good way to handle this case.
     
  3. Lieene-Guo

    Lieene-Guo

    Joined:
    Aug 20, 2013
    Posts:
    547
    As a walkaround, you can do:
    Code (CSharp):
    1.            var WriteToDataAccess = GetComponentDataFromEntity<WriteToData>(false);
    2.             var job1Handle = Entities.WithNativeDisableContainerSafetyRestriction(WriteToDataAccess).WithAll<ExclusionTag>().ForEach((Entity entity) =>
    3.             {
    4.                 WriteToDataAccess[entity] = new WriteToData() { Value = 1 };
    5.                 // Some work
    6.             }).Schedule(Dependency);
    7.  
    8.             var job2Handle = Entities.WithNativeDisableContainerSafetyRestriction(WriteToDataAccess).WithNone<ExclusionTag>().ForEach((Entity entity) =>
    9.             {
    10.                 WriteToDataAccess[entity] = new WriteToData() { Value = 1 };
    11.                 // Some other work
    12.             }).Schedule(Dependency);
    13.  
    14.             Dependency = JobHandle.CombineDependencies(job1Handle, job2Handle);
     
    TheSmokingGnu and joepl like this.
  4. diesoftgames

    diesoftgames

    Joined:
    Nov 27, 2018
    Posts:
    122
    Interesting idea, thanks!

    @joepl Thanks for confirmation that this just isn't possible atm. Please put me down for a vote to please allow this :)
    Also fwiw, I had to use an IJobChunk in another scenario simply because we don't seem to have an equivalent for ScheduleSingle in Entities.ForEach lambdas. I'm extremely appreciating how much easier it is using Entities.ForEach over jobs (directly), so please put me down for strong votes to have these features added. Thank you!
     
  5. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,261
    This exists. If you are using SystemBase, Schedule is single-threaded and ScheduleParallel is parallel.
     
    diesoftgames likes this.
  6. diesoftgames

    diesoftgames

    Joined:
    Nov 27, 2018
    Posts:
    122
    Hmmm, I'm not very familiar with SystemBase and haven't tried using it yet. My understanding of how this all comes together is probably very imperfect, but it looks like it doesn't have inputDependencies, and it seems like that would be kind of problematic for scheduling in an ideal way.
     
  7. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,261
    Instead of using an input argument and a return value, it uses a property in the class called Dependency. You use it and assign back to it for all jobs. And the lambdas will automatically do this for you if you don't specify JobHandles. It is a slick way of combining ComponentSystem and JobComponentSystem into one.
     
  8. diesoftgames

    diesoftgames

    Joined:
    Nov 27, 2018
    Posts:
    122
    Awesome, thanks so much for the tip!
     
  9. joepl

    joepl

    Unity Technologies

    Joined:
    Jul 6, 2017
    Posts:
    87
  10. diesoftgames

    diesoftgames

    Joined:
    Nov 27, 2018
    Posts:
    122
    Also really good to know, thanks for the follow up!
     
  11. diesoftgames

    diesoftgames

    Joined:
    Nov 27, 2018
    Posts:
    122
    Re: SystemBase: I'm trying out using that now, but it's using ForEachLambdaJobDescription instead of ForEachLambdaJobDescriptionJCS. The documentation links to the standard Entities.ForEach documentation (https://docs.unity3d.com/Packages/com.unity.entities@0.9/manual/ecs_entities_foreach.html) but the non-JCS lambda behaves different. For instance, trying to get a DynamicBuffer in the parameters of the lambda throws an error when I try to do it the same way I do for ForEachLambdaJobDescriptionJCS (`in DynamicBuffer<MyBufferElement> myParam`).

    Code (CSharp):
    1. void EntityQueryBuilder.ForEach(EntityQueryBuilder.F_E action)
    2. The type 'Unity.Entities.DynamicBuffer<MyBufferElement>' cannot be used as type parameter 'T0' in the generic type or method 'EntityQueryBuilder.ForEach<T0>(EntityQueryBuilder.F_D<T0>)'. There is no boxing conversion from 'Unity.Entities.DynamicBuffer<MyBufferElement>' to 'Unity.Entities.IComponentData'.
     
  12. joepl

    joepl

    Unity Technologies

    Joined:
    Jul 6, 2017
    Posts:
    87
    @diesoftgames Can you paste some of the Entities.ForEach that is generating that error in your SystemBase class? The interface for Entities.ForEach in SystemBase should be pretty much the same as in JobComponentSystems except for the differences in scheduling.

    We have some samples (that I believe are compiled as tests in our CI) of using DynamicBuffers in Entities.ForEach in SystemBase:
    https://docs.unity3d.com/Packages/c...cs_entities_foreach.html#component-parameters

    That error actually almost looks like you are referencing Entities in a ComponentSystem instead of a SystemBase or JobComponentSystem.
     
  13. diesoftgames

    diesoftgames

    Joined:
    Nov 27, 2018
    Posts:
    122
    Oh yeah entirely possible my brain just stepped out for a minute and I wrote ComponentSystem instead of SystemBase, I'll give it another try. Thanks for the link! (EDIT: Confirmed I was being dense and had descended my system from ComponentSystem not SystemBase which is why Entities.ForEach lambda params were working unexpectedly. Thanks for catching that!)
     
    Last edited: Apr 28, 2020
  14. diesoftgames

    diesoftgames

    Joined:
    Nov 27, 2018
    Posts:
    122
    Also just because we kind of went off an a tangent with SystemBase, I just wanted to reiterate and clarify that I would still love to be able to use JCS to schedule parallel jobs that operate on the same components if I know they won't overlap (I wind up doing this fairly often and it results in a runtime error). Thanks for listening, @joepl :D
     
    CookieStealer2, Vaarz and cvoigt like this.