Does Combining Corouitines and Threads make sense?

Hello,

i am not sure how to handle this Problem. Im very new to threading, and also never used Croutines in Unity.
I have a Method wich is pretty expensive in a .dll that i call in an Update() every half a second. This makes my Screen lag for 50ms two times per second, wich is unacceptable.

i try to Keep it simple in this example:

private void LateUpdate() {
        if (Time.time >= timeToGo)
        {
            runner.DoSomeWork();
            timeToGo = Time.time + 0.5f;
        }
    }
private void DoSomeWork(){
SomeExpensiveWork(ref Count, ref ids, ref vecs1, ref vecs2, ref vecs3);  //calls a .dll

SomeOtherWork(Count, ids, vecs1, vecs2, vecs3)
}

SomeOtherWork is dependent on the Outputs of SomeExpensiveWork.
My idea was to put “SomeExpensiveWork()” in a thread, and make “DoSomeWork()” a thread wich yields as long as the Thread is still running. I assume the Expensive work is threadsafe for this,
I somehow think this is the wrong Approach even tho it sounds right in the Idea.

I’m assuming when you say this:

You mean:

In which case, yeah, that’s a completely suitable way to deal with it.

Some people have even created little libraries that allow the coroutine to jump back and forth between its own thread and the main thread. Like this one here called ThreadNinja:

1 Like

Yes thats what ment.
Is this the usual way of handling such problems?

thank u for ur fast response

Yes, if you prefer using a more self-made approach or need to dive into how something like this would work, use object locks to make sure your threads and coroutines are in sync. For example

using System.Collections;
using System.Threading;
using UnityEngine;

public class Test : MonoBehaviour
{
    private readonly object threadLock = new object();
    private bool workReady = false;
    private bool threadShutdown = false;
    private int simulatedWork = 0;

    private void OnEnable()
    {
        workReady = false;
        threadShutdown = false;
        Thread workerThread = new Thread(DoThreadedWork);
        workerThread.Start();
        StartCoroutine(WaitForThreadWork());
    }
    private void OnDisable()
    {
        threadShutdown = true;
    }
    private IEnumerator WaitForThreadWork()
    {
        while (!threadShutdown)
        {
            // wait for the threaded work to complete
            while (!workReady)
                yield return null;
            // assuming this needs to happen on the main thread
            // don't let the thread edit our data while we process
            lock (threadLock)
            {
                //SomeOtherWork(Count, ids, vecs1, vecs2, vecs3);
                Debug.LogFormat("Simulating some other work {0}", simulatedWork);
                workReady = false;
            }
        }
    }
    private void DoThreadedWork()
    {
        while (!threadShutdown)
        {
            lock (threadLock)
            {
                //SomeExpensiveWork(ref Count, ref ids, ref vecs1, ref vecs2, ref vecs3);
                Thread.Sleep(50); // simulating expensive work for 50ms
                Interlocked.Increment(ref simulatedWork);
                workReady = true;
            }
            // wait half a second to do work again
            Thread.Sleep(500);
        }
    }
}

‘usual’… eh.

There’s lot of ways to deal with the problem. And since I don’t have specifics about your problem, I could say exactly what the ‘usual’ would be… nor what I would even do.

I would say it’s not unusual to do it this way.

Note, there are newer features that Unity has added, and some people may jump in with suggestions of them. Such as the new ‘jobs’ system:
https://github.com/Unity-Technologies/EntityComponentSystemSamples/blob/master/Documentation/content/job_system.md

But the job system has a very specific use case. And it usually doesn’t really consist of calling outside dll’s. So it probably wouldn’t meet your needs.

But again, who knows, maybe it does. Maybe whatever your external dll does could be refactored into your local domain and written as a job.

:shrugs:

@lordofduct i was sitting for a day learning the new Job System but it seems to me that this is not Fitting my Problem since i work with references, and Jobs dont like references. Also big thanks for showing me the asset “Thread ninja”, seems very interesting and Fitting for my Needs.

@jschieck thank u for your example. i guess i cant get around using object locks since i call the root method every 0.5 sek. I Need a bit more time to read into your example Code tho.

I’m wondering why you are calling something so often that is so slow.

Just to check - is this a DLL where you don’t have access to the code? Also does this DLL contain non-Unity code and is, therefore, safe to run on another thread?

Could you not write a C# manager to run on it’s own thread that would call the DLL regularly but offer a simple lightweight interface for your Unity code to call? Then it would act to decouple your components. If you later find a more efficient implementation of this DLL method, replacing it would be straightforward to do.

@Doug_B your second Approach makes a lot of sense in my case. I am not sure if it is easy to do like that, since i have not just one Class, but a few that work together and rely on each other.
but how i could imagine it would be that a Manager runs on its own Thread and everytime it is finished with a process, it invokes an Event on the main thread.

Regarding the .dll, i constantly scan the enviroment, for that i have an OpenGL plugin attached that Scans that what i see.

If these other classes are your own Unity ones, you could consider using a Dependency Injection approach on the DLL Manager’s interface.

That would work. Or have a shared, thread safe, memory area that the DLL Manager populates with latest results and then sets a flag to say the data is ready for reading. Your Unity code could then just poll the is-ready-flag.

Maybe it is interesting, here is a script I used with switching threads in a coroutine. Maybe that can work too for oyur problem.
Edit: Sorry In hindsight there is more in the background (which I didn’t write myself). There is a whole Coroutine Threading manager which starts the coroutine. So I think this is all useless for you. I thought this was Unity default stuff.

        private IEnumerator FogOfWarProcess ()
        {
            while ( isRunning )
            {
                yield return null; //Not sure why that is for
                if ( !IsVissible )
                {
                    continue;
                }

                yield return UnityCoroutine.Now;
                //Inside Unity Thread
                CollectData ();

                m_FogMap.Apply ();
                m_FogOverlayMap.Apply ();

                yield return ThreadCoroutine.Now;
                //Inside Other Thread

                CalculateFogOfWar ();

                System.Threading.Thread.Sleep ( THREAD_SLEEP_TIME );
            }
        }

//Other stuff
    public sealed class UnityCoroutine
    {
        public static readonly UnityCoroutine Now = new UnityCoroutine ();

        private UnityCoroutine () { }
    }

    public sealed class ThreadCoroutine
    {
        public static readonly ThreadCoroutine Now = new ThreadCoroutine ();

        private ThreadCoroutine () { }
    }

I implemented it like this now, wich is without Coroutines and it is working like this. The Performance is not better a lot than before tho.

  private staticTask task
private void Start(){
task = new Task(() => runner.DoSomeWork());
}

private void LateUpdate() {
        if (Time.time >= timeToGo || task.Status != TaskStatus.Running )
        {
            task.Start();
            timeToGo = Time.time + 0.5f;
        }
    }
private void DoSomeWork(){
SomeExpensiveWork(ref Count, ref ids, ref vecs1, ref vecs2, ref vecs3);  //calls a .dll
SomeOtherWork(Count, ids, vecs1, vecs2, vecs3)
}

My first guess would be that it is expensive to start a Task every time, wich would lead me to implementing it like @Doug_B suggested.
if i comment out the LateUpdate method my app runns smoothly. So something there is still pretty expensive for the main thread it seems.
The app runs on the HoloLens, maybe it has something to do with that?

@McDev02 even tho it sounds easy i prefer not to swap between main thread and another thread inside a Coroutine.

@Doug_B I dont really understand dependency injections, so im not sure if it is easy for me to do it that way

About the main question of thread. I’ve few solutions where I’m combining threads and coroutines. Usually my approach is to start a thread with logic and the coroutine is waiting until the thread is finished.

It make sense depends on problem and solution.

That is very plausible. Just be aware that if you do run another dedicated thread, it will not be able to make Unity API calls directly.

There is no need to use a full dependency injection framework. I was more thinking along the lines of having something like an init method :

partial class CDLLManager
{
    public Init( ObjectINeedOne one, ObjectINeedTwo two )
    {
        m_ObjectOne = one;
        m_ObjectTwo = two;
    }

    ObjectINeedOne  m_ObjectOne;
    ObjectINeedTwo  m_ObjectTwo;
}

This may help maintain a clean decoupled interface to make the DLL Manager easy to replace in the future if you so decided.

Thanks a lot.
I now have only one Task wich runs in the Background, instead of starting a new Task in Update.
The app is pretty smooth right now. I have just a tiny bit lag when i try to capture the current view via WebCamTexture.Play and WebCamTexture.GetPixels32(). But These methods can only run on the Main thread as far as i know. So nothing to do here, but i am quite happy with how it is now.

Thanks again guys.

1 Like

Excellent news. Glad you got it sorted. :slight_smile:

I’ve solution where I’m processing image from other source as Texture. I’m doing this in VR and there is performance most important.

My solution is using Microsoft.Drawing.Bitmap for reading pixel colors data and write it to buffer in background thread. Of course it’s possible to use another library for reading picture pixel colors, depends on platform.
Then standart MonoBehaviour Update() is reading this buffer and it’s using it with Texture SetPixel(). After the background thread is finished main thread call Texture Apply().

Works great and keep performance. Speed of loading picture depends on it’s size, but usually take only few seconds.

a few seconds is quite long in this case.
i have a few ms delay at the Moment (10 ms or less) .
U can Show me ur Code how it is done if u like to, i may try it, but right now i like how it is and Focus on other parts.
Kind Regards

I need to say, we are usually opening pictures of size few MB. Sometimes bigger, like 20MB. If you can open big picture as texture in 10ms I’m more interest about your solution. :smile:

Sorry I can’t share this code. It’s company property.

The WWW class supports loading local files and supports asynchronous loading.
https://docs.unity3d.com/ScriptReference/WWW.html

Another option is to just load the image with the System.IO namespace, and then create a Texture2D from a byte array formed from that using Texture.LoadRawTextureData:
https://docs.unity3d.com/ScriptReference/Texture2D.LoadRawTextureData.html