0
\$\begingroup\$

I have a slow level generation algorithm that freezes the main thread when it runs. I found this post which is exactly the same problem, but predates the Jobs system.

All the jobs examples I found are good for parallelizing a bunch of instances of some function but the JobHandle.Complete() still pauses the main loop until they are done. Is there a way to offload a function that will take several frames to complete with Jobs?

Or am I better off creating a thread manually as suggested in that other post?

Thanks

\$\endgroup\$
0

1 Answer 1

1
\$\begingroup\$

EDIT

The Jobs based answer below can work.

But for anyone who has use case I had (one expensive level generator algorithm to run in background rather than many parallel ones), just using Async/Await Tasks requires much less refactoring. This video was helpful:

https://www.youtube.com/watch?v=oWFJl56IL4Y


Original answer

This seems to work. I didn't realise that it will launch scheduled jobs even if you don't call Complete();.

In fact the job will execute even if you don't call JobHandle.ScheduleBatchedJobs(); but the docs seem to say you should call that, so I'm assuming in more complex code there can be a condition when the job won't pick up. Perhaps I'm wrong about this.

ScheduleBatchedJobs docs

public class JobTest : MonoBehaviour
{
    JobHandle myJob;
    bool started = false;
    bool done = false;
    void Update()
    {
        if (!started)
        {
            if (Time.realtimeSinceStartup > 5)
            {
                print("scheduling");
                myJob = scheduleLongJob();
                JobHandle.ScheduleBatchedJobs(); 
                started = true;
            }
        }

        if (myJob.IsCompleted && started)
        {
            myJob.Complete(); // do I need this? What does it do in this case?
            print("job completed");
            done = true;
        }        
    }
    JobHandle scheduleLongJob()
    {
        LongJob myJob = new LongJob();
        return myJob.Schedule(); 
    }
}

public struct LongJob : IJob
{
    public void Execute()
    {
        float u = 0;
        for (int i = 0; i < 50000000; i++)
        {
            u += math.exp10(math.sqrt(10f));
        }
        Debug.Log(u);
    }
}

\$\endgroup\$
6
  • \$\begingroup\$ Do I see it correctly that the gist of this answer is to check jobHandle.IsCompleted in each Update instead of calling jobHandle.Complete()? If yes, then you might want to write that in the answer. \$\endgroup\$
    – Philipp
    Commented Jun 26, 2022 at 18:19
  • \$\begingroup\$ And is the method scheduleLongJob() really necessary here? Can't you just do myJob = new LongJob().Schedule();? \$\endgroup\$
    – Philipp
    Commented Jun 26, 2022 at 18:21
  • \$\begingroup\$ @Philipp It works without it. Docs said I need it. I'm not clear on what it's for if you don't need it in this case. \$\endgroup\$ Commented Jun 26, 2022 at 18:32
  • 1
    \$\begingroup\$ If you got this from a doc, then it would be nice to link to it. \$\endgroup\$
    – Philipp
    Commented Jun 26, 2022 at 18:32
  • 1
    \$\begingroup\$ The docs say "Calling Complete on a JobHandle returns ownership of that job’s NativeContainer types to the control thread. You need to call Complete on a JobHandle to safely access those NativeContainer types from the control thread again" \$\endgroup\$
    – DMGregory
    Commented Jun 26, 2022 at 19:08

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .