Unity多线程(C#)

前言

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


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

  • 创建线程实例的四种方式
    1.线程执行无参方法

    • 构造语法
      /// <summary>
      /// 初始化 Thread 类的新实例。
      /// </summary>
      /// <param name="start">无参委托对象.</param>
      public Thread(ThreadStart start)
      start
      类型:System.Threading.ThreadStart
      表示开始执行此线程时要调用的方法的 ThreadStart 委托。
    • 实例
      void Start()
      {
      //创建无参线程对象
      Thread thr = new Thread(Func_NoArguments);
      //启动线程
      thr.Start();
      }
      /// <summary>
      /// Function Of No Arguments.
      /// </summary>
      void Func_NoArguments()
      {
      Debug.Log("Run Func_NoArguments");
      }

    2.线程执行有参方法

    • 构造语法
      /// <summary>
      /// 初始化 Thread 类的新实例。
      /// </summary>
      /// <param name="start">有参委托对象.</param>
      public Thread(ParameterizedThreadStart start)
      start
      类型:System.Threading.ParameterizedThreadStart
      一个委托,它表示此线程开始执行时要调用的方法。
      注意:参数只能有一个,且必须为object类型
    • 实例
      void Start()
      {
      //创建有参线程对象
      Thread thr = new Thread(Func_Arguments);
      //启动线程,传入参数
      thr.Start("Lanou");
      }
      /// <summary>
      /// Function Of Have Arguments.
      /// </summary>
      void Func_Arguments(object data)
      {
      Debug.Log("Run Func_Arguments, Data = " + data);
      }

    3.线程执行无参方法,限制线程要使用的最大堆栈大小

    • 构造语法
      /// <summary>
      /// 初始化 Thread 类的新实例。
      /// </summary>
      /// <param name="start">无参委托对象.</param>
      /// <param name="maxStackSize">使用的最大堆栈大小.</param>
      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();
      }
      /// <summary>
      /// Function Of No Arguments.
      /// </summary>
      void Func_NoArguments()
      {
      Debug.Log("Run Func_NoArguments");
      }

    4.线程执行有参方法,限制线程要使用的最大堆栈大小

    • 构造语法
      /// <summary>
      /// 初始化 Thread 类的新实例。
      /// </summary>
      /// <param name="start">有参委托对象.</param>
      /// <param name="maxStackSize">使用的最大堆栈大小.</param>
      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");
      }
      /// <summary>
      /// Function Of Have Arguments.
      /// </summary>
      void Func_Arguments(object data)
      {
      Debug.Log("Run Func_Arguments, Data = " + data);
      }
  • 启动线程(上文已使用)

    • 无参启动
      void Start()
      {
      //创建无参线程对象
      Thread thr = new Thread(Func_NoArguments);

//启动线程
thr.Start();

    }
    /// <summary>
    /// Function Of No Arguments.
    /// </summary>
    void Func_NoArguments()
    {
        Debug.Log("Run Func_NoArguments");
    }
  • 有参启动
    void Start()
    {
    //创建有参线程对象
    Thread thr = new Thread(Func_Arguments);

//启动线程,传入参数
thr.Start("Lanou");

    }
    /// <summary>
    /// Function Of Have Arguments.
    /// </summary>
    void Func_Arguments(object data)
    {
        Debug.Log("Run Func_Arguments, Data = " + data);
    }
  • 常用方法
    • public static void Sleep( int millisecondsTimeout)将当前线程挂起指定的毫秒数。
      millisecondsTimeout
      millisecondsTimeout
      类型:System.Int32
      挂起线程的毫秒数。 如果 millisecondsTimeout 参数的值为零,则该线程会将其时间片的剩余部分让给任何已经准备好运行的、有同等优先级的线程。 如果没有其他已经准备好运行的、具有同等优先级的线程,则不会挂起当前线程的执行。
    • public void Resume()
      继续已挂起的线程。(已过时)
    • public void Abort()
      在调用此方法的线程上引发 ThreadAbortException,以开始终止此线程的过程。 调用此方法通常会终止线程。
    • public void Join()
      阻止调用线程直到线程终止,同时继续执行标准的 COM 和 SendMessage 传送。
    • 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

    • 核心方法
      /// <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;
      }
      

结束语

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,598评论 18 399
  • 一、认识多任务、多进程、单线程、多线程 要认识多线程就要从操作系统的原理说起。 以前古老的DOS操作系统(V 6....
    GT921阅读 1,011评论 0 3
  • 线程状态新建,就绪,运行,阻塞,死亡。 线程同步多线程可以同时运行多个任务,线程需要共享数据的时候,可能出现数据不...
    KevinCool阅读 795评论 0 0
  • 一、线程的生命周期 线程状态转换图: 1、新建状态 用new关键字和Thread类或其子类建立一个线程对象后,该线...
    我是嘻哈大哥阅读 893评论 0 8
  • Tips 学习算法最好的方法并不是编写程序,而是手算 千万不要图快——如果没有足够的时间来实践,那么学的快,忘的也...
    _凉风_阅读 345评论 0 0