I need a unique global counter variable that is incremented inside parallel jobs.
As pointed out from another thread, in Custom job types | Jobs | 0.50.0-preview.9, there’s an example of a Native Counter implementation.
Those are the ways it can work (correct me if I’m wrong):
Interlocked atomic writings, when each thread locks an access and then writes to the variable (i.e. the cache line). This means a single cache line will be used by N threads and as the article says “this is not optimal as it means the same cache line is used by all threads. The way this is generally solved in NativeContainers is to have a local cache per worker thread, which is stored on its own cache line”.
So this leads to the second solution, a shared cache line copied to single-thread local cache lines, then each thread performs an increment on his local cache variable. Original counter is then incremented in the main thread. "Writing the NativeCounter this way significantly reduces the overhead of having multiple threads writing to it. It does, however, come at a price. The cost of getting the count on the main thread has increased significantly since it now needs to check all local caches and sum them up".
So, as far as I got, solution 2 too is not optimal because it needs to perform N sums on main thread. I’m currently uncertain whether game-state counters implemented on monobehaviors (I’m making a hybrid game) would make a big deal out of less performance, with respect to parallel jobs counter. Let alone I have no idea if I can create a variant of the structure NativeCounter described in the link above (usable just in IJobParallelFor) in ScheduleParallel of a foreach. I’m currently having issues using unsafe pointers with foreach. Any thoughts on that? Should I give up on monobehaviors on this?
How many instances in total you may have in a job? 100, 1k, 10k, 100k?
Depending on that, if it is small count like 1k for example, it may be worth just iterate these on main thread.
Also, how often you execute this job?
hello,
if you really want to do it in parallel, you could have a native array of integers that is JobsUtility.MaxJobThreadCount length,
then you would access your counter using the thread id that you can get on jobs with the attribute [NativeSetThreadIndex] safely as only one thread would write to any index at any given time
@Antypodish it’s a mobile game, so even 1000 entities would be unthinkable. It’s a crowd game and the counter is incremented whenever a new member joins the crowd (how often will depend on crowd velocity, number of NPC, and other parameters level designers will play with). For now, since I have time constraints, I’ve done it via monobehavior, as in general I have one GameObject referencing each entity:
//late update
if (!_isFollowing)
{
_isFollowing = _entityManager.GetComponentData<IsFollowingData>(EntityToFollow).Value;
if (_isFollowing)
GameManager.main.FollowingAlliesPoints += 1;
}
that’s not too bad considering that with branch prediction, this branch would run only once for each character. But I definitely want to transfer every game controls to jobs and their data structures as soon as I don’t have too restricted deadlines, keeping gameobjects just for animations.