Unity多线程(C#)

发表于2016-03-02
评论4 4.7k浏览

想免费获取内部独家PPT资料库?观看行业大牛直播?点击加入腾讯游戏学院游戏程序行业精英群

711501594
前言

  在这之前,有很多人在质疑Unity支不支持多线程,事实上Unity是支持多线程的。而提到多线程就要提到Unity非常常用的协程,然而协程并非真正的多线程。协程其实是等某个操作完成之后再执行后面的代码,或者说是控制代码在特定的时机执行。而多线程在Unity渲染和复杂逻辑运算时可以高效的使用多核CPU,帮助程序可以更高效的运行。本篇主要介绍在Unity中如何使用多线程。

  首先引入C#中使用多线程的类库using System.Threading;


一、创建线程实例的四种方式
1、线程执行无参方法
· 构造语法
///
/// 初始化 Thread 类的新实例。
///
/// 无参委托对象.
public Thread(ThreadStart start)
· start
类型:System.Threading.ThreadStart
表示开始执行此线程时要调用的方法的 ThreadStart 委托。
· 实例
void Start()
{
    //创建无参线程对象
    Thread thr = new Thread(Func_NoArguments);
    //启动线程
    thr.Start();
}
///
/// Function Of No Arguments.
///
void Func_NoArguments()
{
    Debug.Log("Run Func_NoArguments");
}
2、线程执行有参方法
· 构造语法
///
/// 初始化 Thread 类的新实例。
///
/// 有参委托对象.
public Thread(ParameterizedThreadStart start)
· start
类型:System.Threading.ParameterizedThreadStart
一个委托,它表示此线程开始执行时要调用的方法。
注意:参数只能有一个,且必须为object类型
· 实例
void Start()
{
    //创建有参线程对象
    Thread thr = new Thread(Func_Arguments);
    //启动线程,传入参数
    thr.Start("Lanou");
}
////// Function Of Have Arguments.
///
void Func_Arguments(object data)
{
    Debug.Log("Run Func_Arguments, Data = " + data);
}
3、线程执行无参方法,限制线程要使用的最大堆栈大小
· 构造语法
///
/// 初始化 Thread 类的新实例。
///
/// 无参委托对象.
/// 使用的最大堆栈大小.
public Thread(ThreadStart start,int maxStackSize)
· start
类型:System.Threading.ThreadStart
表示开始执行此线程时要调用的方法的 ThreadStart 委托。
· maxStackSize
类型:System.Int32
线程要使用的最大堆栈大小(以字节为单位);如果为 0,则使用可执行文件的文件头中指定的默认最大堆栈大小。
重要事项:对于部分受信任的代码,如果 maxStackSize 大于默认堆栈大小,则将其忽略。 不引发异常。
· 实例
void Start()
{
    //创建无参线程对象,限制256KB堆栈大小
    Thread thr = new Thread(Func_NoArguments,262144);
    //启动线程
    thr.Start();
}
///
/// Function Of No Arguments.
///
void Func_NoArguments()
{
    Debug.Log("Run Func_NoArguments");
}
4、线程执行有参方法,限制线程要使用的最大堆栈大小
· 构造语法
///
/// 初始化 Thread 类的新实例。
///
/// 有参委托对象.
/// 使用的最大堆栈大小.
public Thread(ParameterizedThreadStart start,int maxStackSize)
· start
类型:System.Threading.ParameterizedThreadStart
一个委托,它表示此线程开始执行时要调用的方法。
注意:参数只能有一个,且必须为object类型
· maxStackSize
类型:System.Int32
线程要使用的最大堆栈大小(以字节为单位);如果为 0,则使用可执行文件的文件头中指定的默认最大堆栈大小。
重要事项:对于部分受信任的代码,如果 maxStackSize 大于默认堆栈大小,则将其忽略。 不引发异常。
· 实例
void Start()
{
    //创建有参线程对象,限制256KB堆栈大小
    Thread thr = new Thread(Func_Arguments,262144);
    //启动线程,传入参数
    thr.Start("Lanou");
}
///
/// Function Of Have Arguments.
///
void Func_Arguments(object data)
{
    Debug.Log("Run Func_Arguments, Data = " + data);
}

二、启动线程(上文已使用)
· 无参启动
void Start()
{
    //创建无参线程对象
    Thread thr = new Thread(Func_NoArguments);
//启动线程

thr.Start();

}
///
/// Function Of No Arguments.
///
void Func_NoArguments()
{
    Debug.Log("Run Func_NoArguments");
}
· 有参启动
void Start()
{
    //创建有参线程对象
    Thread thr = new Thread(Func_Arguments);
//启动线程,传入参数
thr.Start("Lanou");
}
///
/// Function Of Have Arguments.
///
void Func_Arguments(object data)
{
    Debug.Log("Run Func_Arguments, Data = " + data);
}

三、常用方法
public static void Sleep( int millisecondsTimeout)将当前线程挂起指定的毫秒数。
1、millisecondsTimeoutmillisecondsTimeout 类型:System.Int32 挂起线程的毫秒数。 如果 millisecondsTimeout 参数的值为零,则该线程会将其时间片的剩余部分让给任何已经准备好运行的、有同等优先级的线程。 如果没有其他已经准备好运行的、具有同等优先级的线程,则不会挂起当前线程的执行。
2、public void Resume()继续已挂起的线程。(已过时)
3、public void Abort()在调用此方法的线程上引发 ThreadAbortException,以开始终止此线程的过程。 调用此方法通常会终止线程。
4、public void Join()阻止调用线程直到线程终止,同时继续执行标准的 COM 和 SendMessage 传送。
5、public enum ThreadPriority指定 Thread 的调度优先级。
成员名称描述
AboveNormal可以将 Thread 安排在具有 Highest 优先级的线程之后,在具有 Normal 优先级的线程之前。
BelowNormal可以将 Thread 安排在具有 Normal 优先级的线程之后,在具有 Lowest 优先级的线程之前。
Highest可以将 Thread 安排在具有任何其他优先级的线程之前。
Lowest可以将 Thread 安排在具有任何其他优先级的线程之后。
Normal可以将 Thread 安排在具有 AboveNormal 优先级的线程之后,在具有 BelowNormal 优先级的线程之前。 默认情况下,线程具有 Normal 优先级。

四、通过线程池执行线程
ThreadPool.QueueUserWorkItem 方法 (WaitCallback)

public static bool QueueUserWorkItem(WaitCallback callBack)
callBack 
类型:System.Threading.WaitCallback 一个 WaitCallback,表示要执行的方法。
返回值
类型:System.Boolean
如果此方法成功排队,则为 true;如果无法将该工作项排队,则引发 NotSupportedException。

五、Unity使用多线程注意
1、变量都是共享的(都能指向相同的内存地址)
2、UnityEngine的API不能在分线程运行
3、UnityEngine定义的基本结构(int,float,Struct定义的数据类型)可以在分线程计算,如 Vector3(Struct)可以 , 但Texture2d(class,根父类为Object)不可以。
4、UnityEngine定义的基本类型的函数可以在分线程运行

六、Unity多线程插件
LOOM Multi Threading Framework 1.7 下载地址
LOOM Multi Threading Framework
· 核心方法
 ///
 /// 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.
 ///
 /// 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.
 /// Fired when all re-packaged workLoad-objects are finished computing
 /// Fires foreach finished re-packaged set of workLoad-object
 /// 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)
 /// If Null, a new ThreadPoolScheduler will be instantiated.
 /// Executes all the computations within try-catch events, logging it the message + stacktrace
 /// A ThreadPoolScheduler that handles all the repackaged workLoad-Objects
 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;
}


结束语

  Unity可以使用多线程,但对其有很多限制,所以在不使用UnityEngine API的情况下,可以使用多线程,提高多核CPU的使用率。通常可以将需要大量计算的算法内容,放置到多线程中执行,包括逻辑框架也可以放到多线程中执行。本篇理论性较强,后期会陆续发布实战型文章。

原文链接

著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引

游戏学院公众号二维码
腾讯游戏学院
微信公众号

提供更专业的游戏知识学习平台