前言
在這之前,有很多人在質(zhì)疑Unity支不支持多線程宫仗,事實(shí)上Unity是支持多線程的彻坛。而提到多線程就要提到Unity非常常用的協(xié)程,然而協(xié)程并非真正的多線程荐虐。協(xié)程其實(shí)是等某個(gè)操作完成之后再執(zhí)行后面的代碼七兜,或者說(shuō)是控制代碼在特定的時(shí)機(jī)執(zhí)行。而多線程在Unity渲染和復(fù)雜邏輯運(yùn)算時(shí)可以高效的使用多核CPU福扬,幫助程序可以更高效的運(yùn)行腕铸。本篇主要介紹在Unity中如何使用多線程。
首先引入C#中使用多線程的類庫(kù)
using System.Threading;
-
創(chuàng)建線程實(shí)例的四種方式
1.線程執(zhí)行無(wú)參方法- 構(gòu)造語(yǔ)法
/// <summary>
/// 初始化 Thread 類的新實(shí)例铛碑。
/// </summary>
/// <param name="start">無(wú)參委托對(duì)象.</param>
public Thread(ThreadStart start)
start
類型:System.Threading.ThreadStart
表示開(kāi)始執(zhí)行此線程時(shí)要調(diào)用的方法的 ThreadStart 委托狠裹。
- 實(shí)例
void Start()
{
//創(chuàng)建無(wú)參線程對(duì)象
Thread thr = new Thread(Func_NoArguments);
//啟動(dòng)線程
thr.Start();
}
/// <summary>
/// Function Of No Arguments.
/// </summary>
void Func_NoArguments()
{
Debug.Log("Run Func_NoArguments");
}
2.線程執(zhí)行有參方法
- 構(gòu)造語(yǔ)法
/// <summary>
/// 初始化 Thread 類的新實(shí)例。
/// </summary>
/// <param name="start">有參委托對(duì)象.</param>
public Thread(ParameterizedThreadStart start)
start
類型:System.Threading.ParameterizedThreadStart
一個(gè)委托汽烦,它表示此線程開(kāi)始執(zhí)行時(shí)要調(diào)用的方法涛菠。
注意:參數(shù)只能有一個(gè),且必須為object類型 - 實(shí)例
void Start()
{
//創(chuàng)建有參線程對(duì)象
Thread thr = new Thread(Func_Arguments);
//啟動(dòng)線程,傳入?yún)?shù)
thr.Start("Lanou");
}
/// <summary>
/// Function Of Have Arguments.
/// </summary>
void Func_Arguments(object data)
{
Debug.Log("Run Func_Arguments, Data = " + data);
}
3.線程執(zhí)行無(wú)參方法,限制線程要使用的最大堆棧大小
- 構(gòu)造語(yǔ)法
/// <summary>
/// 初始化 Thread 類的新實(shí)例俗冻。
/// </summary>
/// <param name="start">無(wú)參委托對(duì)象.</param>
/// <param name="maxStackSize">使用的最大堆棧大小.</param>
public Thread(ThreadStart start,int maxStackSize)
start
類型:System.Threading.ThreadStart
表示開(kāi)始執(zhí)行此線程時(shí)要調(diào)用的方法的 ThreadStart 委托礁叔。
maxStackSize
類型:System.Int32
線程要使用的最大堆棧大小(以字節(jié)為單位)言疗;如果為 0晴圾,則使用可執(zhí)行文件的文件頭中指定的默認(rèn)最大堆棧大小。
重要事項(xiàng):對(duì)于部分受信任的代碼噪奄,如果 maxStackSize 大于默認(rèn)堆棧大小死姚,則將其忽略。 不引發(fā)異常勤篮。
- 實(shí)例
void Start()
{
//創(chuàng)建無(wú)參線程對(duì)象,限制256KB堆棧大小
Thread thr = new Thread(Func_NoArguments,262144);
//啟動(dòng)線程
thr.Start();
}
/// <summary>
/// Function Of No Arguments.
/// </summary>
void Func_NoArguments()
{
Debug.Log("Run Func_NoArguments");
}
4.線程執(zhí)行有參方法都毒,限制線程要使用的最大堆棧大小
- 構(gòu)造語(yǔ)法
/// <summary>
/// 初始化 Thread 類的新實(shí)例。
/// </summary>
/// <param name="start">有參委托對(duì)象.</param>
/// <param name="maxStackSize">使用的最大堆棧大小.</param>
public Thread(ParameterizedThreadStart start,int maxStackSize)
start
類型:System.Threading.ParameterizedThreadStart
一個(gè)委托碰缔,它表示此線程開(kāi)始執(zhí)行時(shí)要調(diào)用的方法账劲。
注意:參數(shù)只能有一個(gè),且必須為object類型
maxStackSize
類型:System.Int32
線程要使用的最大堆棧大薪鹇铡(以字節(jié)為單位)瀑焦;如果為 0,則使用可執(zhí)行文件的文件頭中指定的默認(rèn)最大堆棧大小梗肝。
重要事項(xiàng):對(duì)于部分受信任的代碼榛瓮,如果 maxStackSize 大于默認(rèn)堆棧大小,則將其忽略巫击。 不引發(fā)異常禀晓。
- 實(shí)例
void Start()
{
//創(chuàng)建有參線程對(duì)象,限制256KB堆棧大小
Thread thr = new Thread(Func_Arguments,262144);
//啟動(dòng)線程,傳入?yún)?shù)
thr.Start("Lanou");
}
/// <summary>
/// Function Of Have Arguments.
/// </summary>
void Func_Arguments(object data)
{
Debug.Log("Run Func_Arguments, Data = " + data);
}
- 構(gòu)造語(yǔ)法
-
啟動(dòng)線程(上文已使用)
- 無(wú)參啟動(dòng)
void Start()
{
//創(chuàng)建無(wú)參線程對(duì)象
Thread thr = new Thread(Func_NoArguments);
- 無(wú)參啟動(dòng)
//啟動(dòng)線程
thr.Start();
}
/// <summary>
/// Function Of No Arguments.
/// </summary>
void Func_NoArguments()
{
Debug.Log("Run Func_NoArguments");
}
- 有參啟動(dòng)
void Start()
{
//創(chuàng)建有參線程對(duì)象
Thread thr = new Thread(Func_Arguments);
//啟動(dòng)線程,傳入?yún)?shù)
thr.Start("Lanou");
}
/// <summary>
/// Function Of Have Arguments.
/// </summary>
void Func_Arguments(object data)
{
Debug.Log("Run Func_Arguments, Data = " + data);
}
-
常用方法
- public
static
voidSleep
( int millisecondsTimeout)將當(dāng)前線程掛起指定的毫秒數(shù)。
millisecondsTimeout
millisecondsTimeout
類型:System.Int32
掛起線程的毫秒數(shù)坝锰。 如果 millisecondsTimeout 參數(shù)的值為零,則該線程會(huì)將其時(shí)間片的剩余部分讓給任何已經(jīng)準(zhǔn)備好運(yùn)行的粹懒、有同等優(yōu)先級(jí)的線程。 如果沒(méi)有其他已經(jīng)準(zhǔn)備好運(yùn)行的顷级、具有同等優(yōu)先級(jí)的線程凫乖,則不會(huì)掛起當(dāng)前線程的執(zhí)行。 - public void
Resume
()
繼續(xù)已掛起的線程弓颈。(已過(guò)時(shí)) - public void
Abort
()
在調(diào)用此方法的線程上引發(fā) ThreadAbortException拣凹,以開(kāi)始終止此線程的過(guò)程。 調(diào)用此方法通常會(huì)終止線程恨豁。 - public void
Join
()
阻止調(diào)用線程直到線程終止,同時(shí)繼續(xù)執(zhí)行標(biāo)準(zhǔn)的 COM 和 SendMessage 傳送爬迟。 - public enum
ThreadPriority
指定 Thread 的調(diào)度優(yōu)先級(jí)橘蜜。
- public
成員名稱 | 描述 |
---|---|
AboveNormal | 可以將 Thread 安排在具有 Highest 優(yōu)先級(jí)的線程之后,在具有 Normal 優(yōu)先級(jí)的線程之前。 |
BelowNormal | 可以將 Thread 安排在具有 Normal 優(yōu)先級(jí)的線程之后计福,在具有 Lowest 優(yōu)先級(jí)的線程之前跌捆。 |
Highest | 可以將 Thread 安排在具有任何其他優(yōu)先級(jí)的線程之前。 |
Lowest | 可以將 Thread 安排在具有任何其他優(yōu)先級(jí)的線程之后象颖。 |
Normal | 可以將 Thread 安排在具有 AboveNormal 優(yōu)先級(jí)的線程之后佩厚,在具有 BelowNormal 優(yōu)先級(jí)的線程之前。 默認(rèn)情況下说订,線程具有 Normal 優(yōu)先級(jí)抄瓦。 |
-
通過(guò)線程池執(zhí)行線程
- ThreadPool.
QueueUserWorkItem
方法 (WaitCallback)
public static boolQueueUserWorkItem
(WaitCallback callBack)
callBack
類型:System.Threading.WaitCallback
一個(gè) WaitCallback,表示要執(zhí)行的方法陶冷。
返回值
類型:System.Boolean
如果此方法成功排隊(duì)钙姊,則為 true;如果無(wú)法將該工作項(xiàng)排隊(duì)埂伦,則引發(fā) NotSupportedException煞额。
- ThreadPool.
-
Unity使用多線程注意
- 變量都是共享的(都能指向相同的內(nèi)存地址)
- UnityEngine的API不能在分線程運(yùn)行
- UnityEngine定義的基本結(jié)構(gòu)(int,float,Struct定義的數(shù)據(jù)類型)可以在分線程計(jì)算,如 Vector3(Struct)可以 沾谜, 但Texture2d(class,根父類為Object)不可以膊毁。
- UnityEngine定義的基本類型的函數(shù)可以在分線程運(yùn)行
-
Unity多線程插件
LOOM Multi Threading Framework 1.7 下載地址
LOOM Multi Threading Framework-
核心方法
/// <summary>
/// Unlike "StartMultithreadedWorkloadExecution", you will have to build your own IThreadWorkerObject.
/// Downside: It requires some extra work. Upside: you got more controll over what goes in and comes out
/// Infact: You can create you own polymorphed IThreadWorkerObject-array, each ellement being a completely different type. For example: the statemachines of enemies are IThreadWorkerObject's and the array contains completely different classes with enemies/AI-behaviours.
/// </summary>
/// <param name="workerObjects">An array of IThreadWorkerObject objects to be handled by the threads. If you want multiple cores/threads to be active, make sure that the number of IThreadWorkerObject's proves matches/exeeds your preferred number maxWorkingThreads. </param>
/// <param name="onComplete">Fired when all re-packaged workLoad-objects are finished computing</param>
/// <param name="onPackageExecuted">Fires foreach finished re-packaged set of workLoad-object</param>
/// <param name="maxThreads"> Lets you choose how many threads will be run simultaneously by the threadpool. Default: -1 == number of cores minus one, to make sure the MainThread has at least one core to run on. (quadcore == 1 core Mainthread, 3 cores used by the ThreadPoolScheduler)</param>
/// <param name="scheduler">If Null, a new ThreadPoolScheduler will be instantiated.</param>
/// <param name="safeMode">Executes all the computations within try-catch events, logging it the message + stacktrace</param>
/// <returns>A ThreadPoolScheduler that handles all the repackaged workLoad-Objects</returns>
public static ThreadPoolScheduler StartMultithreadedWorkerObjects(IThreadWorkerObject[] workerObjects, ThreadPoolSchedulerEvent onCompleteCallBack, ThreadedWorkCompleteEvent onPackageExecuted = null, int maxThreads = -1, ThreadPoolScheduler scheduler = null, bool safeMode = true)
{
if (scheduler == null)
scheduler = CreateThreadPoolScheduler();scheduler.StartASyncThreads(workerObjects, onCompleteCallBack, onPackageExecuted, maxThreads, safeMode); return scheduler; }
-
結(jié)束語(yǔ)
Unity可以使用多線程,但對(duì)其有很多限制基跑,所以在不使用UnityEngine API的情況下婚温,可以使用多線程,提高多核CPU的使用率涩僻。通崇哉伲可以將需要大量計(jì)算的算法內(nèi)容,放置到多線程中執(zhí)行逆日,包括邏輯框架也可以放到多線程中執(zhí)行嵌巷。本篇理論性較強(qiáng),后期會(huì)陸續(xù)發(fā)布實(shí)戰(zhàn)型文章室抽。