[Job System] output scalar value from job

I started playing around with the new job system.

I tried to create a ‘sum’ job like this:

struct SerialSumJob : IJob
    {
        [ReadOnly]
        public NativeArray<float> data;
        public float output;

        public void Execute ()
        {
            var len = data.Length;
            output = 0;
            for (int i = 0; i < len; i++) {
                output += data[i];
            }
        }
    }

and running it with

var job = new SerialSumJob { data = data };
            job.Schedule ().Complete();
            Debug.LogFormat ("job complete: {0}", job.output);

(data was initialized with Random values)

after job was complete, output was still 0.

it makes sense, as structs get copied, but is there a recommended way to enable it? (i can workaround with a single-element NativeArray)

You have to use the single-element NativeArray, there is no other way.

2 Likes

ok. slightly feels like a hack though.

is there something planned for it? like

public struct SumJob : IJob<float> {
    [ReadOnly] public NativeArray<float> values;

    public float Execute() {return 42f;}
}
...
var result = new SumJob{values = ...}.Schedule().Complete();

Could you post a code example of what you mean? Still trying to get my head around the nativearray use and job use for basics such as creating a job that will increment a value…

Nevermind, worked it out :slight_smile: lightning fast speeds, parallel operations are a great thing!

2 Likes

No, nothing is planned. Single-element arrays have been considered to be the best approach for the moment.

Would be nice to know what the threading model is here. Like can we mix what would be normal in a concurrent environment here with jobs.

For example if output was declared outside of IJob, and not touched until the job was complete, that would be completely normal in any low latency concurrent app. If you don’t actually need memory barriers, you don’t create them just for the fun of it.

Or if we can use api’s like Interlocked in jobs.

The threading model would basically answer all questions of that type.

Actually would be nice to have some serious docs and blog time on this subject, it’s basically a ground-breaking feature in my view.

Think for a moment. Threading this easy, without race conditions etc ? wow!

2 Likes

yep, totally agree.

I guess they’re going to share details, documentation, etc… when they officially announce the release of the new tech. So far, even though it’s included in Unity, the official statement is “Coming soon: the C# Job System”.

I’m surprised the job system even allowed a public float non native array without a [ReadOnly] in front.

So the job is an actual struct. So what we do internally, is we take all data on the struct copy it out and give it to the job. So its perfectly fine to write back to the float on the job (Because the changed values are only visible on that thread and then discarded), this has no negative impact on performance or determinism.

Arguably its a bit of a strange thing to do and maybe usually a mistakes. I guess we could argue that a static analysis tool should tell the user that writing to the float is likely not making any sense and at least output a warning.

2 Likes

it can make sense to write to a float, to count the area of occupation of one force in an RTS or the pollution level of the land.

i dont understand how N thread writing to the same value is deterministic… i thought that if thread 1 and 2 do value++ then at the end of one round there is a chance that you get only value++ instead of the expected value=value+2

Each thread will receive its own copy of the original struct in the Execute method. So it is deterministic.

In any case, I think we can agree that writing to value types on the jobs is undesirable and static analysis too should prevent users from doing it.

2 Likes

Does that means a Job is able to calculate area of occupation or pollution level of a grid but ForJob will return an erroneous result?
If that’s the case then value types should be allowed on jobs but not on ForJobs

I take it back, some examples would be great!

2020, any new ways to do this? I was very confused that my code didn’t work.

at least emit errors in the console.

1 Like

I have a wrapper for this:

public struct NativeUnit<T> where T : struct {
    private NativeArray<T> internalContainer;

    public NativeUnit(Allocator allocator) {
        this.internalContainer = new NativeArray<T>(1, allocator);
    }

    public void Dispose() {
        this.internalContainer.Dispose();
    }

    public T Value {
        get {
            return this.internalContainer[0];
        }

        set {
            this.internalContainer[0] = value;
        }
    }
}
2 Likes

Unity.Collections has NativeReference
https://docs.unity3d.com/Packages/com.unity.collections@0.11/api/Unity.Collections.NativeReference-1.html

3 Likes

This has bitten me a few times. You’d think a person would remember, but people don’t because it’s counter-intuitive. I get the why under the hood, but I wish for a way to not get such a productivity tax for these weird nuances.

Maybe give us something like NativeInt, etc, to help people remember.

1 Like