简体   繁体   English

如何在没有主线程的情况下使用统一的“ JobSystem”,而不冻结?

[英]How to use unity “JobSystem” Without main thread , And not freeze?

I want to use that load some in backgound , But Jobsystem probably use the main thread , So how to do use jobsystem Wituhot Freezes , is it impossible ?? 我想在backgound中使用该负载,但是Jobsystem可能使用主线程,那么如何使用Jobsystem Wituhot Freezes做作业,这是不可能的吗? Or I just use C# Thread?? 还是我只使用C#线程? Dont Use JobSystem ?? 不要使用JobSystem?

struct SleepJob : IJobParallelFor
{
    public void Execute(int index)
    {
        Debug.LogFormat("[SleepJob.Execute] Thread Id {0}", Thread.CurrentThread.ManagedThreadId);
        Thread.Sleep(1);
    }
}
struct SleepJob2 : IJobParallelFor
{
    public void Execute(int index)
    {
        Debug.LogFormat("[SleepJob2.Execute] Thread Id {0}", Thread.CurrentThread.ManagedThreadId);
        Thread.Sleep(1);
    }
}
[ContextMenu("JobSleep")]
public void JobSleep()
{
    Debug.LogFormat("[JobSleep.Execute] Thread Id {0}", Thread.CurrentThread.ManagedThreadId);

    SleepJob job = new SleepJob() { };
    SleepJob2 job2 = new SleepJob2() { };
    JobHandle jh = job.Schedule(100, 64);
    JobHandle jh2 = job2.Schedule(100, 64, jh);
    JobHandle.ScheduleBatchedJobs();
    jh2.Complete(); // freezes

    Debug.LogFormat("[JobSleep.Execute] jh.Complete();");
}

Make JobHandle jh2 global variable. 使JobHandle jh2全局变量。 Check JobHandle.isComplete in Update method or in Coroutine 在Update方法或协程中检查JobHandle.isComplete

Note that Complete makes your execution freeze because: 请注意, Complete会使您的执行冻结,因为:

The JobSystem automatically prioritizes the job and any of its dependencies to run first in the queue, then attempts to execute the job itself on the thread which calls the Complete function . JobSystem自动对作业及其任何依赖项进行优先级排序,使其首先在队列中运行,然后尝试在调用Complete函数的线程上执行作业本身。

I think this is not the method you want to use. 我认为这不是您要使用的方法。

Rather try waiting for the Job to complete in a Coroutine like eg 而是尝试在协同程序中等待作业完成,例如

[ContextMenu("JobSleep")]
public void JobSleep()
{
    Debug.LogFormat("[JobSleep.Execute] Thread Id {0}", Thread.CurrentThread.ManagedThreadId);

    SleepJob job = new SleepJob() { };
    SleepJob2 job2 = new SleepJob2() { };
    JobHandle jh = job.Schedule(100, 64);
    JobHandle jh2 = job2.Schedule(100, 64, jh);
    JobHandle.ScheduleBatchedJobs();

    StartCoroutine(WaitFor(jh2));
}

IEnumerator WaiFor(JobHandle job)
{
    yield return new WaitUntil(() => job.IsComplete);

    Debug.LogFormat("[JobSleep.Execute] job IsComplete");
}

Unfortunately you didn't add the code you actually want to be executed in background. 不幸的是,您没有添加要在后台执行的代码。

In general maybe simply using a Thread or async might already solve your problem. 通常,简单地使用Threadasync可能已经解决了您的问题。

eg with a Thread 例如带Thread

// for sending back responses to the main thread
private ConcurrentQueue<Action> callbacks = new ConcurrentQueue<Action>;

// work the callbacks in the main thread
private void Update()
{
    while(callbacks.Count > 0)
    {
        Action callback;
        if(callbacks.TryDequeue(out callback)) callback?.Invoke();
    }
}

// optional callback on success
public void StartBackgroundTask(Action onSuccess = null)
{
    var thread = new Thread(new ParameterizedThreadStart(TheTaskThatTakesAWhile);
    // pass in parameters here
    thread.Start(onSuccess);
}

// Will be running in a background thread
private void TheTaskThatTakesAWhile(Action onSuccess)
{
    // hand this back to the main thread
    callbacks.Enqueue(() => Debug.Log("Long task started ..."));

    // TODO whatever takes so long

    // Note btw that sleep is in milliseconds!
    Thread.Sleep(1000);

    hand this back to the mainthread
    callbacks.Enqueue(() => 
    {
        Debug.Log("Long task started ..."));

        onSuccess?.Invoke();
    }
}

eg using async (which internally also runs in a Thread) 例如使用async (它也在内部在线程中运行)

private async Task TheTaskThatTakesAWhile()
{
    // do whatever takes long here
}

// usually you should avoid having async void
// but when including an Action as callback this is fine
public async void StartBackgroundTask(Action onSuccess = null)
{
    await TheTaskThatTakesAWhile();

    onSuccess?.Invoke();
}

Both you could call like eg 你们两个都可以像

StartBackgroundTask(() => {
    // what should happen when done?

    Debug.Log("I'm done!");
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM