Are there any substantial reasons to use the IJobChunk workflow over the Entities.ForEach workflow?

Apologies if this question is very basic.

I cannot figure out when i should use the IJobChunk workflow or the Entities.ForEach workflow when iterating over entities in a system. The reason that this concerns me, is that i see many examples employing both. I tried finding an answer in the ECS manual but all i found is this, which is quite vague. The one clear point it makes is that optional components can be processed with the IJobChunk workflow. This is not something i have seen used though.

So the question is; when should i use which?

1 Like

Use IJobChunk when Entities.ForEach is not sufficient to do what you want to do.

Here’s a real-world example of using IJobChunk to process optional components and unique combinations. Yes it is a little complicated. Usually if you need to use IJobChunk, you are doing something fairly complicated. Latios-Framework/Physics/Physics/Internal/Builders/BuildCollisionLayerInternal.cs at v0.2.1 · Dreaming381/Latios-Framework · GitHub

1 Like

Just wanted to add a personal opinion that I think IJobChunk are great when learning - Entities.ForEach feels a lot less magical after getting comfortable with them. In particular things like how you pass a CDFE to a static method and how it relates to GetComponent<> in SystemBase. Also, like DreamingImLatios hinted at - optional components - when you want to branch logic on e.g. the presence of a Tag and are in the hot path and don’t want to duplicate code to solve it. As IJobChunk iterates the chunks (rather than entities) you can branch or early out on the chunk level.

1 Like

Thanks a lot for the fast answers. If it’s the case that IJobChunk are great when learning, i will use them.

2 Likes

They are a lot more verbose so I wouldn’t recommend you write a lot of them but I think they are a good fundamental part of Unity’s ECS to understand - it’s what the Entities.ForEach compiles to. Good luck :slight_smile:

1 Like

I can chime in to say that we use IJobChunk for most of our jobs. Here are the main reasons:

  1. You can schedule more than one IJobChunk per system update. That’s not supported (or at least didn’t used to be supported) for Entities.ForEach.

  2. we make good use of generic jobs in our code. They live in a shared namespace, and explicit instances of them are scheduled by multiple systems. That’s not possible with Entities.ForEach.

  3. IJobChunk gives you lower level control over how a job functions. Unity does a good job of translating Entities.ForEach jobs into high performance jobs for you. But working directly at the IJobChunk level can give you more awareness and peace of mind. Personal preference, this one. :slight_smile:

  4. I believe there may still be some equivalent things you can’t do in Entities.ForEach, like decorating job variables with edge-case attributes. But time has passed since I ran into that, so maybe that part has changed.

it’s funny that people have described them as a learning tool to use at the beginning. Because I’ve seen them as the opposite - Entities.ForEach is the one to use early on, since it does a lot of things magically. It tries to be more convenient, but sacrifices some control, visibility, and features to get there.

Then when you want to do something ForEach doesn’t support, you drop down to a lower level and start writing more IJobChunks, since they give you more visibility and control.

In my opinion, the lambda part of ForEach was a good idea for a way to make writing jobs more convenient. But in order for ForEach jobs to capture variables, you end up needing to write unintuitive code, like define them above the ForEach declaration without actually doing anything with them until later. I don’t think it’s a convention you would design into your code for any other reason, other than to make the capturing work.

And personally, I think that variables defined in an IJob or IJobChunk struct are much more readable than stacking a dozen “.With()” functions as part of the ForEach syntax. Personal opinion there.

5 Likes

Sometimes I wonder how much time you have… I wish I had the time to do things like these as well. I’ve been spending a year on a mesh builder that if given a full-time treatment would have been finished already. However, I have a 9-5 that takes up more than enough of my time.

1 Like

You also can’t currently get chunk component data in a ForEach, if you’re even aware that’s a thing, most people aren’t.

1 Like

Not enough, but somehow more than you despite also having a day job?

1 Like

How long did it take you and what are you using it for?

1 Like

The particular job? This is like the third or fourth iteration, each of which I did in a few hours on one of my weekends. This provides more insight into what it is used for: Latios-Framework/Documentation~/Optimization Adventures/Part 2 - Build Collision Layer 1.md at v0.2.1 ¡ Dreaming381/Latios-Framework ¡ GitHub

Unless you are referring to the framework as a whole? In that case, link to the forum thread is in my signature.

Also, I did a dig through my public repos and this is actually my only usage of IJobChunk currently in those. I have one case where I use IJobFor on a NativeArray using DynamicComponentTypeHandles, but otherwise I use Entities.ForEach way more often.

3 Likes

Can you or someone else eleborate on this? I have a bunch of Entities.ForEach in SystemBases. What is their behavior then?

3 Likes

You may want to verify (or hopefully someone else where can verify) that my claim is even true anymore.

but when Entities.ForEach was first introduced, I believe you could only schedule one of them in a system’s update function. At the time, if you needed to schedule several, sequential jobs from a single system, Unity was advising people to use IJobChunk and other explicit job structs.

If you’re able to use multiple, sequential Entities.ForEach calls from a single system Update function, then maybe this limitation has been removed. My apologies - I can’t test this at the moment or I’d verify it as well.

1 Like

You can use multiple .ForEach in a single OnUpdate now. You just need to be careful about dependencies between the jobs.

you might need to call JobHandle.Complete() or JobHandle.CombineDependencies().

1 Like

I don’t ever remember any requirement of a single ForEach, could be wrong. Either way, no there is no limitation on how many ForEachs. AFAIK ForEach gets converted into an IJobChunk during codegen.

If anything Entities.ForEach lets you ignore job handles most of the time. I suggest you read up on it.

1 Like

Thank you @Sarkahn_1 ! I was referencing needing to pass data in and out of these .ForEach()'s (like this ) where you need to be mindful of when jobs are completed and what data you reference.

2 Likes

It never was like this :slight_smile: From the ForEach beginning, you can use many of them in one OnUpdate.

1 Like

CDFE? what’s that

(Get)ComponentDataFromEntity - what backs the Has/Get/SetComponent calls inside a SystemBase - sometimes useful for example to capture and pass to a static method within the lambda when working with Entities.ForEach

Guessing here (also not a big fan of acronyms for exactly this reason: unclear what they mean):
ComponentDataFromEntity

https://docs.unity3d.com/Packages/com.unity.entities@0.16/api/Unity.Entities.ComponentDataFromEntity-1.html