Unity-线程工具(一)
程序员文章站
2022-06-11 08:03:31
...
进程、线程以及协程的特点:
1)进程:一般一个程序对应一个进程,进程是操作系统级别的概念。
2)线程:主线程、子线程、线程池、资源的加锁访问,并且它是并行的。单独的线程的执行由操作系统管理(这实际上取决于.NET实现)。 当有多个“逻辑”CPU时,许多线程就能够在不同的CPU上同时执行。多线程的使用情况:大量耗时的数据计算、网络请求(http请求、Socket等)、文件I/O操作、AI、寻路等。
3)协程:Unity主线程的协程,不是独立的线程,它是并发的。协程方法可以一段接一段时间地执行,但“节奏”仍由一个主线程来控制。当一个协程尝试执行耗时的操作,整个应用程序会出现卡顿的情况。
4)线程与主线程之间的交互通信同步:子线程一般不允许直接访问Unity主线程的API,但可以通过委托中介来实现。【借鉴Loom插件的实现思路】
本人在学习了Loom插件之后,借鉴了其实现原理,按照自己的理解,重写了一个任务异步执行的工具。欢迎大家讨论发表建议!
MainThreadHelper.cs类:主要是为了子线程中可以访问Unity主线程的API。这样实现了子线程和主线程之间访问通信。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading;
using System;
/*
* Author:W
* 单任务主线程处理工具
*
*/
namespace W.GameFramework.MultiThread
{
//主线程处理的委托函数声明
public delegate void MainThreadHandler();
public delegate void MainThreadHandlerWithArg(object arg);
public delegate object MainThreadHandlerWithReturn();
public delegate object MainThreadHandlerWithArgAndReturn(object arg);
/// <summary>
/// 主线程执行的任务封装
/// </summary>
public class MainThreadTask
{
private bool finished = false;
/// <summary>
/// 主线程任务是否完成
/// </summary>
public bool Finished
{
get { return finished; }
}
private object result;
/// <summary>
/// 主线程任务执行完成返回的结果
/// </summary>
public object Result
{
get { return result; }
}
/// <summary>
/// 该主线程任务传入的参数
/// </summary>
private object argParam;
//执行主线程任务的函数类型
private MainThreadHandler mainThreadHandler;
private MainThreadHandlerWithArg mainThreadHandlerWithArg;
private MainThreadHandlerWithReturn mainThreadHandlerWithReturn;
private MainThreadHandlerWithArgAndReturn mainThreadHandlerWithArgAndReturn;
/// <summary>
/// 既不带参数也没有返回的任务
/// </summary>
/// <param name="mainThreadHandler"></param>
/// <param name="waitForExcution"></param>
public MainThreadTask(MainThreadHandler mainThreadHandler,bool waitForExcution)
{
this.mainThreadHandler = mainThreadHandler;
CheckExcution(waitForExcution);
}
/// <summary>
/// 带参数但没有返回的任务
/// </summary>
/// <param name="mainThreadHandlerWithArg"></param>
/// <param name="param"></param>
/// <param name="waitForExecution"></param>
public MainThreadTask(MainThreadHandlerWithArg mainThreadHandlerWithArg, object param, bool waitForExecution)
{
this.mainThreadHandlerWithArg = mainThreadHandlerWithArg;
this.argParam = param;
CheckExcution(waitForExecution);
}
/// <summary>
/// 不带参数,但有返回的任务
/// 【注意】这种类型的任务,因为需要等待处理结果,所以一般设定为“强制优先处理型”
/// </summary>
/// <param name="mainThreadHandlerWithReturn"></param>
public MainThreadTask(MainThreadHandlerWithReturn mainThreadHandlerWithReturn)
{
this.mainThreadHandlerWithReturn = mainThreadHandlerWithReturn;
CheckExcution(true);
}
/// <summary>
/// 带参数,并且有返回的任务
/// 【注意】这种类型的任务,因为需要等待处理结果,所以一般设定为“强制优先处理型”
/// </summary>
/// <param name="mainThreadHandlerWithArgAndReturn"></param>
/// <param name="param"></param>
public MainThreadTask(MainThreadHandlerWithArgAndReturn mainThreadHandlerWithArgAndReturn,object param)
{
this.mainThreadHandlerWithArgAndReturn = mainThreadHandlerWithArgAndReturn;
this.argParam = param;
CheckExcution(true);
}
/// <summary>
/// 检查该主线程任务是否可以现在执行,如果不可以,则开始“休眠”当前的分线程,
/// 目的:让CPU拿出资源来优先执行主线程任务。
/// </summary>
/// <param name="waitForExcution">是否强制优先处理主线程任务</param>
private void CheckExcution(bool waitForExcution)
{
if (waitForExcution)
{
//如果发现当前已经主线程,则立即执行该主线程任务
if (MainThreadHelper.CheckIsMainThread())
{
ExcuteTask();
}
else
{
//如果当前不是主线程,该任务未执行,并且当前游戏App处于活跃状态
//让当前分线程间歇性休眠,让出CPU资源
while (!finished && UnityAppMonitor.Instance.Active)
{
Thread.Sleep(5);
}
}
}
}
/// <summary>
/// 主线程任务执行
/// </summary>
public void ExcuteTask()
{
try
{
if (mainThreadHandler != null)
{
mainThreadHandler();
}
else if (mainThreadHandlerWithArg != null)
{
mainThreadHandlerWithArg(argParam);
}
else if (mainThreadHandlerWithReturn != null)
{
result = mainThreadHandlerWithReturn();
}
else if (mainThreadHandlerWithArgAndReturn != null)
{
result = mainThreadHandlerWithArgAndReturn(argParam);
}
}
catch (Exception e)
{
UnityEngine.Debug.LogError(e.Message);
}
finished = true;
}
}
/// <summary>
/// 单任务:主线程处理工具
/// 1.检查当前运行的是否是主线程,如果是,则立即执行该任务;
/// 2.如果不是,则将该任务缓存到“待处理主线程任务池”中,定期检查是否可以执行;
/// 3.对于紧急优先要处理的主线程任务, 如果当前运行的是非主线程,则需要“强制”休眠它,
/// 使它让出CPU资源,给主线程。
/// </summary>
public class MainThreadHelper
{
#region 主线程判断
private static Thread mainThread = null;
/// <summary>
/// 检查当前线程是否是主线程
/// </summary>
/// <returns></returns>
public static bool CheckIsMainThread()
{
return Thread.CurrentThread == mainThread;
}
#endregion
/// <summary>
/// 初始化
/// </summary>
public static void Init()
{
if (mainThread == null)
{
Thread curThread = Thread.CurrentThread;
if (curThread.GetApartmentState() == ApartmentState.MTA || curThread.ManagedThreadId > 1
|| curThread.IsThreadPoolThread)
{
Debug.Log("当前线程Thread=" + curThread.Name + " 是分线程,非主线程");
}
else
{
mainThread = curThread;
}
}
}
/// <summary>
/// 主线程待处理的任务集
/// </summary>
private static List<MainThreadTask> mainThreadTasks = new List<MainThreadTask>();
/// <summary>
/// 主线程任务处理
/// </summary>
public static void DealWithTasks()
{
if (mainThreadTasks == null || mainThreadTasks.Count == 0) return;
lock (mainThreadTasks)
{
for (int i = 0; i < mainThreadTasks.Count; i++)
{
if (!mainThreadTasks[i].Finished)
mainThreadTasks[i].ExcuteTask();
}
mainThreadTasks.Clear();
//打开门,放所有等待队列中的线程到就绪队列
Monitor.PulseAll(mainThreadTasks);
}
}
/// <summary>
/// 在主线程执行该任务
/// [不带参数,也没有返回]
/// </summary>
/// <param name="mainThreadHandler">被执行的函数</param>
/// <param name="waitForExecution">是否强制CPU优先执行该主线程任务</param>
public static void DealTaskByMainThread(MainThreadHandler mainThreadHandler, bool waitForExecution = false)
{
//如果检查到当前就是主线程,则立即执行
if (CheckIsMainThread())
{
if (mainThreadHandler != null)
mainThreadHandler();
} //否则,加入到主线任务缓存队列,让系统自动选择时机执行
else
{
MainThreadTask task = new MainThreadTask(mainThreadHandler,waitForExecution);
lock (mainThreadTasks) { mainThreadTasks.Add(task); }
}
}
/// <summary>
/// 在主线程执行该任务
/// 【带参数,但没有返回】
/// </summary>
/// <param name="mainThreadHandlerWithArg"></param>
/// <param name="param"></param>
/// <param name="waitForExecution"></param>
public static void DealTaskWithArgByMainThread(MainThreadHandlerWithArg mainThreadHandlerWithArg, object param, bool waitForExecution)
{
//如果检查到当前就是主线程,则立即执行
if (CheckIsMainThread())
{
if (mainThreadHandlerWithArg != null)
mainThreadHandlerWithArg(param);
} //否则,加入到主线任务缓存队列,让系统自动选择时机执行
else
{
MainThreadTask task = new MainThreadTask(mainThreadHandlerWithArg,param,waitForExecution);
lock (mainThreadTasks) { mainThreadTasks.Add(task); }
}
}
/// <summary>
/// 在主线程执行该任务
/// 【不带参数,但有返回值】
/// </summary>
/// <param name="mainThreadHandlerWithReturn"></param>
/// <returns></returns>
public static object DealTaskWithReturnByMainThread(MainThreadHandlerWithReturn mainThreadHandlerWithReturn)
{
//如果检查到当前就是主线程,则立即执行
if (CheckIsMainThread())
{
if (mainThreadHandlerWithReturn != null)
return mainThreadHandlerWithReturn();
}//否则,加入到主线任务缓存队列,让系统自动选择时机执行
else
{
MainThreadTask task = new MainThreadTask(mainThreadHandlerWithReturn);
lock (mainThreadTasks) { mainThreadTasks.Add(task); }
return task.Result;
}
return null;
}
/// <summary>
/// 在主线程执行该任务
/// 【带参数,有返回值】
/// </summary>
/// <param name="mainThreadHandlerWithArgAndReturn"></param>
/// <param name="param"></param>
/// <returns></returns>
public static object DealTaskWithArgAndReturnByMainThread(MainThreadHandlerWithArgAndReturn mainThreadHandlerWithArgAndReturn,object param)
{
//如果检查到当前就是主线程,则立即执行
if (CheckIsMainThread())
{
if (mainThreadHandlerWithArgAndReturn != null)
return mainThreadHandlerWithArgAndReturn(param);
}//否则,加入到主线任务缓存队列,让系统自动选择时机执行
else
{
MainThreadTask task = new MainThreadTask(mainThreadHandlerWithArgAndReturn,param);
lock (mainThreadTasks) { mainThreadTasks.Add(task); }
return task.Result;
}
return null;
}
}
}