Unity zero basis to advanced | the use of multithreading in unity, ordinary Thread creation + using the Loom plug-in

preface

  • Multithreading is not commonly used in Unity, so the knowledge about it is not particularly thorough
  • So this article will briefly talk about the role, limitations and usage of multithreading in Unity

Use of multithreading in Unity

In Unity, in addition to the main thread responsible for UI drawing, there are also co processes and multi threads.

The coroutine is accompanied by the "start" program of the main thread, which allows the program to run some methods within a specific time. The coroutine can call some UI and other attributes in Unity.

However, multithreading cannot directly process the game objects in Unity, because in Unity, you can only get the components, methods and game objects of the object in the main thread!

Use multithreading to:

  • To load and configure download resources with threads, you need to display a progress bar
  • Data processing in algorithm

What can be tuned using multithreading:

  • C # basic variables
  • In addition to the content in the API of UnityEngine
  • Some basic structures defined by UnityEngined can also be called. For example, vector3 (structure) can be called, but Texture2d(class, root directory is Object) cannot.

Method 1: create multithreading in a normal way

Using Thread to open up a child Thread in Unity

Then, some business processes such as data calculation, value transfer and interaction with Android are carried out in this sub thread.

However, some API s in Unity cannot be called

Examples are as follows:

using System.Collections.Generic;
using System.Threading;
using UnityEngine;
using UnityEngine.UI;
public class ThreadTest : MonoBehaviour
{
    void Start() 
    {
        //Open up a child thread
        Thread childThread1 = new Thread(CallToChildThread);
        childThread1.Start();
    }

    //What the child thread is responsible for
    public void CallToChildThread()
    {
        //Call the contents of the main thread
         Debug.Log(test());
         //Print result: 666
    }
    
    int test()
    {
        return 666;
    }
}

Method 2: use the Loom plug-in to make multi-threaded calls

When Unity uses multithreaded development, one is to use the Loom plug-in for multithreading

Room is a tool class that is specifically responsible for the interaction between the main thread and the sub thread in Unity. The room plug-in has only one script, which can be imported and used in Unity

Which uses Loom to open up a sub thread method

        Loom.RunAsync(() =>
        {
            Thread childThread = new Thread(CallToChildThread);
            childThread.Start();
        });

Call the data method in Unity using Loom multithreading:

        //Use room to call the contents of the main thread
        Loom.QueueOnMainThread((param) =>
        {
            ThreadTxt.text = "The child thread is turned on";
        }, null);

The complete code example of calling the main thread with a child thread is as follows:

using System.Threading;
using UnityEngine;
using UnityEngine.UI;
public class ThreadTest : MonoBehaviour
{
    public Text ThreadTxt;
    void Start()
    {
        //Using Loom to open up a child thread
        Loom.RunAsync(() =>
        {
            Thread childThread = new Thread(CallToChildThread);
            childThread.Start();
        });
    }

    public void CallToChildThread()
    {
        //Use room to call the contents of the main thread
        Loom.QueueOnMainThread((param) =>
        {
            ThreadTxt.text = "The child thread is turned on";
        }, null);
    }
}

The tool class code of the room plug-in is as follows:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
using System.Threading;
using System.Linq;

public class Loom : MonoBehaviour
{
    public static int maxThreads = 8;
    static int numThreads;

    private static Loom _current;
    //private int _count;
    public static Loom Current
    {
        get
        {
            Initialize();
            return _current;
        }
    }

    void Awake()
    {
        _current = this;
        initialized = true;
    }

    static bool initialized;

    public static void Initialize()
    {
        if (!initialized)
        {

            if (!Application.isPlaying)
                return;
            initialized = true;
            var g = new GameObject("Loom");
            _current = g.AddComponent<Loom>();
#if !ARTIST_BUILD
            UnityEngine.Object.DontDestroyOnLoad(g);
#endif
        }

    }
    public struct NoDelayedQueueItem
    {
        public Action<object> action;
        public object param;
    }

    private List<NoDelayedQueueItem> _actions = new List<NoDelayedQueueItem>();
    public struct DelayedQueueItem
    {
        public float time;
        public Action<object> action;
        public object param;
    }
    private List<DelayedQueueItem> _delayed = new List<DelayedQueueItem>();

    List<DelayedQueueItem> _currentDelayed = new List<DelayedQueueItem>();

    public static void QueueOnMainThread(Action<object> taction, object tparam)
    {
        QueueOnMainThread(taction, tparam, 0f);
    }
    public static void QueueOnMainThread(Action<object> taction, object tparam, float time)
    {
        if (time != 0)
        {
            lock (Current._delayed)
            {
                Current._delayed.Add(new DelayedQueueItem { time = Time.time + time, action = taction, param = tparam });
            }
        }
        else
        {
            lock (Current._actions)
            {
                Current._actions.Add(new NoDelayedQueueItem { action = taction, param = tparam });
            }
        }
    }

    public static Thread RunAsync(Action a)
    {
        Initialize();
        while (numThreads >= maxThreads)
        {
            Thread.Sleep(100);
        }
        Interlocked.Increment(ref numThreads);
        ThreadPool.QueueUserWorkItem(RunAction, a);
        return null;
    }

    private static void RunAction(object action)
    {
        try
        {
            ((Action)action)();
        }
        catch
        {
        }
        finally
        {
            Interlocked.Decrement(ref numThreads);
        }

    }


    void OnDisable()
    {
        if (_current == this)
        {

            _current = null;
        }
    }



    // Use this for initialization
    void Start()
    {

    }

    List<NoDelayedQueueItem> _currentActions = new List<NoDelayedQueueItem>();

    // Update is called once per frame
    void Update()
    {
        if (_actions.Count > 0)
        {
            lock (_actions)
            {
                _currentActions.Clear();
                _currentActions.AddRange(_actions);
                _actions.Clear();
            }
            for (int i = 0; i < _currentActions.Count; i++)
            {
                _currentActions[i].action(_currentActions[i].param);
            }
        }

        if (_delayed.Count > 0)
        {
            lock (_delayed)
            {
                _currentDelayed.Clear();
                _currentDelayed.AddRange(_delayed.Where(d => d.time <= Time.time));
                for (int i = 0; i < _currentDelayed.Count; i++)
                {
                    _delayed.Remove(_currentDelayed[i]);
                }
            }

            for (int i = 0; i < _currentDelayed.Count; i++)
            {
                _currentDelayed[i].action(_currentDelayed[i].param);
            }
        }
    }
}

summary

  • There are many inconveniences in using multithreading in Unity. Generally speaking, with the existence of coprocessing, multithreading will not be used again

  • Including using the Loom plug-in is not particularly convenient

  • Therefore, different people have different opinions. If you encounter some non particularly complex operations, you can use the collaborative process!

  • Xie Cheng's learning articles are here. Interested partners can come and have a look!

Unity zero foundation to getting started ☀️| Little ten thousand words tutorial on the collaborative process in unity ❤️ Comprehensive analysis + actual combat drill ❤️

Tags: Unity Multithreading

Posted on Fri, 29 Oct 2021 04:17:20 -0400 by ScoTi