欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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;
		}
    }
}

下篇文章链接点击进入