前言
- 在Unity中多執行緒其實并不常用,所以關于這塊的知識也沒有去研究的特別透徹
- 所以本篇文章就來簡單說一下多執行緒在Unity中的作用、限制以及用法
Unity中的多執行緒的使用
Unity中除了主執行緒負責UI等繪制之外,還有協程、多執行緒可以使用,
其中協程伴隨著 主執行緒 ?起運?的?段程式,讓程式在特定的時間內運行某些方法,協程是可以對Unity中的一些UI等屬性進行方法呼叫的,
但是多執行緒并不能直接去處理Unity中的游戲物件,因為在Unity中,只能在主執行緒中去獲取物體的組件、方法和游戲物件!
使用多執行緒的作用:
- 用執行緒加載配置下載資源,需要顯示進度條
- 進行演算法方面的資料處理
使用多執行緒可以調的內容:
- C#基本的變數
- 除了UnityEngine的API中的內容
- UnityEngined定義的一些基本結構也可以,比如Vector3(struct)可以呼叫,但是Texture2d(class,根目錄為Object)就不可以,
方法一:普通方式創建多執行緒
在Unity中使用Thread開辟一個子執行緒
然后在這個子執行緒中進行一些資料的計算、傳值、與Android互動等業務處理,
但是并不能呼叫Unity中的一些API
示例如下:
using System.Collections.Generic;
using System.Threading;
using UnityEngine;
using UnityEngine.UI;
public class ThreadTest : MonoBehaviour
{
void Start()
{
//開辟一個子執行緒
Thread childThread1 = new Thread(CallToChildThread);
childThread1.Start();
}
//子執行緒負責處理的事情
public void CallToChildThread()
{
//呼叫主執行緒的內容
Debug.Log(test());
//列印結果:666
}
int test()
{
return 666;
}
}
方法二:使用Loom插件進行多執行緒的呼叫
常見的Unity使用多執行緒開發時,有一種是使用Loom插件進行多執行緒的使用
Loom是一個專門負責Unity中主執行緒與子執行緒互動的一個工具類,Loom插件只有一個腳本,在Unity中匯入使用即可
其中使用Loom開辟一個子執行緒方法
Loom.RunAsync(() =>
{
Thread childThread = new Thread(CallToChildThread);
childThread.Start();
});
使用Loom多執行緒呼叫Unity中的資料方法:
//使用Loom呼叫主執行緒的內容
Loom.QueueOnMainThread((param) =>
{
ThreadTxt.text = "子執行緒開啟了";
}, null);
完整示例如下使用子執行緒呼叫主執行緒 的代碼示例如下:
using System.Threading;
using UnityEngine;
using UnityEngine.UI;
public class ThreadTest : MonoBehaviour
{
public Text ThreadTxt;
void Start()
{
//使用Loom開辟一個子執行緒
Loom.RunAsync(() =>
{
Thread childThread = new Thread(CallToChildThread);
childThread.Start();
});
}
public void CallToChildThread()
{
//使用Loom呼叫主執行緒的內容
Loom.QueueOnMainThread((param) =>
{
ThreadTxt.text = "子執行緒開啟了";
}, null);
}
}
Loom插件的工具類代碼如下:
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);
}
}
}
}
總結
-
Unity中使用多執行緒有很多不方便的地方,一般來說有了協程的存在,也不會再去使用多執行緒
-
包括使用Loom插件其實也不是特別的方便
-
所以大家仁者見仁,遇到一些不是特別復雜的運算等情況使用協程就好啦!
-
協程的學習文章在這里,感興趣的小伙伴可以來看看哦!
Unity零基礎到入門 ??| 小萬字教程 對 Unity 中的 協程 ??全面決議+實戰演練??

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/341981.html
標籤:其他
上一篇:分橘子問題-日本著名數學游戲專家中村義作教授提出這樣一個問題:父親將2520個桔子分給六個兒子...
下一篇:關于猜數字游戲的實作
