Unity多線程管理
游戲中我們有許多地方還是有需求要開啟多線程,例如下載文件,解壓文件等操作,我們需要在Unity下使用
多線程,那我們如何能更方便的管理多線程呢?
目前主要需要解決一下幾個問題:
- 統一開啟子線程,防止多線程濫用
- 子線程中如何回調主線程
我目前的解決方案
- 所有需要異步處理的任務,都繼承
AsyncTask
。 -
AsyncTask
封裝了執行過程,方便對任務的控制。 - 所有需要回調主線程的地方,統一添加
Action
。由主線程逐幀調用
代碼如下:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;
using LuaFramework;
/// <summary>
/// 異步任務,交給子線程執行
/// </summary>
public abstract class AsyncTask
{
// multiThreadMgr
protected MultiThreadManager MultiThreadMgr {
get {
return AppFacade.Instance.GetManager<MultiThreadManager> (ManagerName.MultiThread);
}
}
/// <summary>
/// 執行任務
/// </summary>
public void Execute() {
try {
Run();
} finally {
MultiThreadMgr.FinishTask (this);
}
}
/// <summary>
/// 關閉執行
/// </summary>
public abstract void Close ();
/// <summary>
/// 開始運行
/// </summary>
public abstract void Run ();
}
/// <summary>
/// 多線程管理器
/// </summary>
public class MultiThreadManager : Manager
{
// 需要在主線程執行的操作
static List<Action> actions = new List<Action> ();
static List<Action> runningActions = new List<Action> ();
static object obj = new object();
// 異步任務隊列
static List<AsyncTask> taskList = new List<AsyncTask> ();
/// <summary>
/// 在主線程中執行
/// </summary>
/// <param name="action">Action.</param>
public void RunOnMainThread (Action action)
{
lock (obj) {
actions.Add (action);
}
}
/// <summary>
/// 添加異步任務
/// </summary>
/// <param name="runnable">Runnable.</param>
public void AddAsyncTask (AsyncTask runnable)
{
Debug.Log("AddTask:" + runnable.ToString());
taskList.Add (runnable);
Thread thread = new Thread (runnable.Execute);
thread.IsBackground = true;
thread.Start ();
}
/// <summary>
/// 完成異步任務
/// </summary>
/// <param name="runnable">Runnable.</param>
public void FinishTask (AsyncTask runnable)
{
taskList.Remove (runnable);
Debug.Log ("RemoveTask:" + runnable.ToString () + "," + taskList.Count);
}
/// <summary>
/// 主線程更新
/// </summary>
void Update ()
{
lock (obj) {
runningActions.Clear ();
runningActions.AddRange (actions);
actions.Clear ();
}
// 處理主線程事件
if (runningActions.Count > 0) {
foreach(Action action in runningActions) {
action ();
}
}
runningActions.Clear ();
}
void OnDestroy() {
for (int i = 0; i < taskList.Count; i++) {
taskList [i].Close ();
}
}
}