統一多線程(C#)

前言

在這之前,有很多人在質疑統一支不支持多線程,事實上統一是支持多線程的。而提到多線程就要提到統一非常常用的協程,然而協程並非真正的多線程。協程其實是等某個操作完成之後再執行後面的代碼,或者說是控制代碼在特定的時機執行。而多線程在統一渲染和複雜邏輯運算時可以高效的使用多核CPU,幫助程序可以更高效的運行。本篇主要介紹在團結中如何使用多線程。


  • 首先引入C#中使用多線程的類庫 using System.Threading;
  • 創建線程實例的四種方式 1.線程執行無參方法
    • 構造語法/// <summary>

      /// 初始化 Thread 類的新實例。

      /// </summary>

      /// <param name="start">無參委託對象.</param>

      public Thread(ThreadStart 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)

開始類型: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)

開始類型: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)

開始類型: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 staticvoid Sleep(int millisecondsTimeout)將當前線程掛起指定的毫秒數。millisecondsTimeout millisecondsTimeout

      類型:System.Int32

      掛起線程的毫秒數。 如果 millisecondsTimeout 參數的值為零,則該線程會將其時間片的剩餘部分讓給任何已經準備好運行的、有同等優先順序的線程。 如果沒有其他已經準備好運行的、具有同等優先順序的線程,則不會掛起當前線程的執行。

    • public void Resume()繼續已掛起的線程。(已過時)
    • public void Abort()在調用此方法的線程上引發 ThreadAbortException,以開始終止此線程的過程。 調用此方法通常會終止線程。

    • public void Join()阻止調用線程直到線程終止,同時繼續執行標準的 COM 和 SendMessage 傳送。
    • 公開枚舉 ThreadPriority指定 Thread 的調度優先順序。

成員名稱 描述 超出正常水平 可以將線程安排在具有最高優先順序的線程之後,在具有普通優先順序的線程之前。 低於一般 可以將線程安排在具有普通優先順序的線程之後,在具有最低優先順序的線程之前。 最高 可以將線程安排在具有任何其他優先順序的線程之前。 最低 可以將線程安排在具有任何其他優先順序的線程之後。 正常 可以將線程安排在具有以上正常優先順序的線程之後,在具有低於正常優先順序的線程之前。線程具有普通優先順序。

  • 通過線程池執行線程
    • ThreadPool。QueueUserWorkItem方法(WaitCallback) public static bool QueueUserWorkItem(WaitCallback callBack) callBack 類型:System.Threading.WaitCallback

      一個 WaitCallback,表示要執行的方法。

返回值 類型:System.Boolean 如果此方法成功排隊,則為 true;如果無法將該工作項排隊,則引發 NotSupportedException。

  • 統一使用多線程注意
    1. 變數都是共享的(都能指向相同的內存地址)
    2. UnityEngine的API不能在分線程運行
    3. UnityEngine定義的基本結構(int,float,Struct定義的數據類型)可以在分線程計算,如Vector3(Struct)可以,但Texture2d(class,根父類為Object)不可以。
    4. UnityEngine定義的基本類型的函數可以在分線程運行
  • Unity多線程插件 LOOM Multi Threading Framework 1.7 下載地址

LOOM多線程框架

    • 核心方法

/// <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 IThreadWorkerObjects 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 IThreadWorkerObjects 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的使用率。通常可以將需要大量計算的演算法內容,放置到多線程中執行,包括邏輯框架也可以放到多線程中執行。本篇理論性較強,後期會陸續發布實戰型文章。

推薦閱讀:

TAG:手機遊戲開發 | Unity遊戲引擎 | 多線程編程 |