上篇介绍了SingleThreadHelper类,ThreadPoolHelper.cs和MultiThreadedTaskLoadHelper.cs:前者实现使用的线程池ThresdPool和协程Coroutine来处理多任务;后者是在它基础上的再封装和扩展,以方便外界访问。
实现如下
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading;
using System;
/*
* Author:W
* 多任务并行处理工具
* 1.使用线程池来处理
* 2.开启协程来处理
*/
namespace W.GameFramework.MultiThread
{
/// <summary>
/// 线程任务接口
/// </summary>
public interface IThreadTask
{
/// <summary>
/// 执行任务
/// </summary>
void ExecuteTask();
/// <summary>
/// 停止任务
/// </summary>
void AbortTask();
}
/// <summary>
/// 线程任务信息封装
/// </summary>
public class ThreadTaskInfo
{
public IThreadTask threadTask;
/// <summary>
/// 任务是否开始
/// </summary>
public bool Started { get; set; }
/// <summary>
/// 任务是否在执行中
/// </summary>
public bool Running { get; set; }
/// <summary>
/// 任务是否完成
/// </summary>
public bool Finished { get; set; }
/// <summary>
/// 任务事件是否触发
/// </summary>
public bool EventFired { get; set; }
public AutoResetEvent resetEvent;
/// <summary>
/// 执行任务
/// </summary>
/// <param name="obj"></param>
public void ExecuteTask(object obj)
{
if (threadTask == null || resetEvent == null) return;
Running = true;
try
{
threadTask.ExecuteTask();
}
catch (Exception e)
{
//输出Log日志NotDo
}
Running = false;
Finished = true;
//Debug.Log("线程任务执行完成");
//通知返回主线程
resetEvent.Set();
}
}
/// <summary>
/// 异步线程处理的任务数据封装
/// </summary>
public class AsyncThreadTaskData
{
/// <summary>
/// 所有的线程任务信息
/// </summary>
public ThreadTaskInfo[] threadTaskInfos;
/// <summary>
/// 任务最大的处理线程数
/// </summary>
public int maxThreads;
public AsyncThreadTaskData(IThreadTask[] threadTasks, int maxWorkingThreads = -1)
{
if (threadTasks == null) return;
threadTaskInfos = new ThreadTaskInfo[threadTasks.Length];
for (int i = 0; i < threadTasks.Length; i++)
{
ThreadTaskInfo threadTaskInfo = new ThreadTaskInfo();
threadTaskInfo.threadTask = threadTasks[i];
threadTaskInfo.resetEvent = new AutoResetEvent(false);
threadTaskInfos[i] = threadTaskInfo;
}
if (maxWorkingThreads <= 0)
{
maxWorkingThreads = Mathf.Max(SystemInfo.processorCount - 1, 1);
}
maxThreads = maxWorkingThreads;
}
/// <summary>
/// 数据清空
/// </summary>
public void Clear()
{
if (threadTaskInfos == null) return;
for (int i = 0; i < threadTaskInfos.Length; i++)
{
ThreadTaskInfo threadTaskInfo = threadTaskInfos[i];
if (threadTaskInfo.resetEvent != null)
threadTaskInfo.resetEvent.Close();
threadTaskInfo.resetEvent = null;
threadTaskInfo.threadTask = null;
}
threadTaskInfos = null;
}
}
/// <summary>
/// 线程池调度事件委托
/// </summary>
/// <param name="threadTasks"></param>
public delegate void ThreadPoolSchedulerHandler(IThreadTask[] threadTasks);
/// <summary>
/// 线程任务完成事件委托
/// </summary>
/// <param name="threadTask"></param>
public delegate void ThreadTaskFinishHandler(IThreadTask threadTask);
/// <summary>
/// 多任务:线程池或协程处理工具
/// </summary>
public class ThreadPoolHelper : MonoBehaviour
{
/// <summary>
/// 是否切换到主线程,使用协程来执行
/// </summary>
public bool ForceToMainThread = false;
/// <summary>
/// 等待时间
/// </summary>
public float WaitForSeconds = 0.001f;
/// <summary>
/// 需要执行的所有任务数据
/// </summary>
private AsyncThreadTaskData asyncThreadTaskData;
/// <summary>
/// 所有任务执行完成的回调
/// </summary>
private ThreadPoolSchedulerHandler threadPoolSchedulerHandler;
/// <summary>
/// 当前任务执行完成的回调
/// </summary>
private ThreadTaskFinishHandler threadTaskFinishHandler;
/// <summary>
/// 线程池的调度线程
/// </summary>
private Thread providerThread;
private bool providerThreadBusy;
private int taskIndex;
private bool isBusy;
/// <summary>
/// 线程调度是否忙
/// </summary>
public bool IsBusy
{
get { return isBusy; }
}
/// <summary>
/// 异步线程是否停止
/// </summary>
private bool isAborted;
/// <summary>
/// 当前任务的完成进度
/// </summary>
public float Progress
{
get
{
if (asyncThreadTaskData == null || asyncThreadTaskData.threadTaskInfos == null
|| asyncThreadTaskData.threadTaskInfos.Length == 0)
return 1f;
int finishedTaskNum = 0;
for (int i = 0; i < asyncThreadTaskData.threadTaskInfos.Length; i++)
{
if (asyncThreadTaskData.threadTaskInfos[i].Finished)
finishedTaskNum++;
}
return (float)finishedTaskNum / asyncThreadTaskData.threadTaskInfos.Length;
}
}
/// <summary>
/// 异步执行多任务
/// 1.协程执行多任务
/// 2.线程池执行多任务
/// </summary>
/// <param name="threadTasks"></param>
/// <param name="threadPoolSchedulerHandler"></param>
/// <param name="threadTaskFinishHandler"></param>
/// <param name="maxThreads"></param>
public void DealTaskByAsyncThreads(IThreadTask[] threadTasks,ThreadPoolSchedulerHandler threadPoolSchedulerHandler,ThreadTaskFinishHandler threadTaskFinishHandler = null,
int maxThreads = -1)
{
if (isBusy)
{
Debug.LogError("异步线程调度繁忙中,下次再尝试");
return;
}
if (threadTasks == null || threadTasks.Length == 0)
{
Debug.LogError("没有需要异步执行的任务,请检查");
return;
}
isBusy = true;
this.threadPoolSchedulerHandler = threadPoolSchedulerHandler;
this.threadTaskFinishHandler = threadTaskFinishHandler;
//没要求一定是主线程来执行的任务
if (!ForceToMainThread)
{
providerThreadBusy = true;
isAborted = false;
StartCoroutine("WaitForCompletion");
asyncThreadTaskData = new AsyncThreadTaskData(threadTasks,maxThreads);
providerThread = new Thread(new ThreadStart(InvokeASyncThreadPoolTask));
providerThread.Start();
}//启动协程来执行
else
{
StartCoroutine(WaitAndExecuteTasks(threadTasks));
}
}
/// <summary>
/// 开启调度线程
/// </summary>
public void InvokeASyncThreadPoolTask()
{
ThreadManager.Instance.SleepOrAbortIfUnityInactive();
//总任务数
int totalTasks = asyncThreadTaskData.threadTaskInfos.Length;
//计算处理上述任务需要的总线程数
int threads = Mathf.Clamp(asyncThreadTaskData.maxThreads,1,totalTasks);
//优先处理的一批任务加入到线程池任务队列中
for (int i = 0; i < threads && !isAborted; i++)
{
if (asyncThreadTaskData.threadTaskInfos[i] != null)
{
asyncThreadTaskData.threadTaskInfos[i].Started = true;
ThreadPool.QueueUserWorkItem(asyncThreadTaskData.threadTaskInfos[i].ExecuteTask,i);
}
}
//剩余的要处理的任务根据实时情况,加入到线程池任务队列中
taskIndex = threads;
while (taskIndex < totalTasks && !isAborted)
{
ThreadManager.Instance.SleepOrAbortIfUnityInactive();
//检查当前开始了的任务执行情况,如果未执行完,等待它们完成先
AutoResetEvent[] autoResetEvents = GetStartedTaskResetEvents();
if (autoResetEvents.Length > 0)
WaitHandle.WaitAny(autoResetEvents);
//然后再添加后续任务
asyncThreadTaskData.threadTaskInfos[taskIndex].Started = true;
ThreadPool.QueueUserWorkItem(asyncThreadTaskData.threadTaskInfos[taskIndex].ExecuteTask,taskIndex);
taskIndex++;
}
//再做一次检查,查看各线程任务执行状况
AutoResetEvent[] pendingResetEvents = GetStartedTaskResetEvents();
if (pendingResetEvents.Length > 0)
{
ThreadManager.Instance.SleepOrAbortIfUnityInactive();
WaitHandle.WaitAll(pendingResetEvents);
}
providerThreadBusy = false;
}
/// <summary>
/// 线程任务执行状态检查
/// </summary>
private IEnumerator WaitForCompletion()
{
while (!isAborted)
{
yield return new WaitForSeconds(WaitForSeconds);
//线程已停止,跳出检测
if (isAborted) break;
//检查已经完成的任务但未分发事件,这里执行分发
int unHandledFinishedTaskCount = GetUnHandledFinishedTaskCount();
if (unHandledFinishedTaskCount > 0)
{
for (int i = 0; i < asyncThreadTaskData.threadTaskInfos.Length; i++)
{
ThreadTaskInfo threadTaskInfo = asyncThreadTaskData.threadTaskInfos[i];
if (threadTaskInfo.Finished && !threadTaskInfo.EventFired)
{
if (threadTaskFinishHandler != null)
threadTaskFinishHandler(threadTaskInfo.threadTask);
threadTaskInfo.EventFired = true;
}
}
}
//所有线程任务已经完成,跳出检测
int finishedTaskCount = GetFinishedTaskCount();
if (finishedTaskCount == asyncThreadTaskData.threadTaskInfos.Length)
break;
}
//所有线程任务执行完成后
if (!isAborted)
{
IThreadTask[] threadTasks = GetThreadTasksFromTaskData();
asyncThreadTaskData.Clear();
asyncThreadTaskData = null;
isBusy = false;
if (threadPoolSchedulerHandler != null)
threadPoolSchedulerHandler(threadTasks);
}
}
/// <summary>
/// 从任务数据中获取所有执行任务
/// </summary>
/// <returns></returns>
private IThreadTask[] GetThreadTasksFromTaskData()
{
if (asyncThreadTaskData == null || asyncThreadTaskData.threadTaskInfos == null)
return new IThreadTask[0];
IThreadTask[] threadTasks = new IThreadTask[asyncThreadTaskData.threadTaskInfos.Length];
for (int i = 0; i < asyncThreadTaskData.threadTaskInfos.Length; i++)
{
threadTasks[i] = asyncThreadTaskData.threadTaskInfos[i].threadTask;
}
return threadTasks;
}
/// <summary>
/// 获取已经完成了但事件未触发的任务数量
/// </summary>
/// <returns></returns>
private int GetUnHandledFinishedTaskCount()
{
if (asyncThreadTaskData == null || asyncThreadTaskData.threadTaskInfos == null)
return 0;
int count = 0;
for (int i = 0; i < asyncThreadTaskData.threadTaskInfos.Length; i++)
{
if (asyncThreadTaskData.threadTaskInfos[i].Finished && !asyncThreadTaskData.threadTaskInfos[i].EventFired)
count++;
}
return count;
}
/// <summary>
/// 获取已经完成了的任务数量
/// </summary>
/// <returns></returns>
private int GetFinishedTaskCount()
{
if (asyncThreadTaskData == null || asyncThreadTaskData.threadTaskInfos == null)
return 0;
int count = 0;
for (int i = 0; i < asyncThreadTaskData.threadTaskInfos.Length; i++)
{
if (asyncThreadTaskData.threadTaskInfos[i].Finished)
count++;
}
return count;
}
/// <summary>
/// 获取已开始任务的resetevent事件
/// </summary>
/// <returns></returns>
private AutoResetEvent[] GetStartedTaskResetEvents()
{
List<AutoResetEvent> autoResetEvents = new List<AutoResetEvent>();
for (int i = 0; i < asyncThreadTaskData.threadTaskInfos.Length; i++)
{
ThreadTaskInfo threadTaskInfo = asyncThreadTaskData.threadTaskInfos[i];
if (threadTaskInfo.Started && !threadTaskInfo.Finished)
autoResetEvents.Add(threadTaskInfo.resetEvent);
}
return autoResetEvents.ToArray();
}
/// <summary>
/// 使用协程处理任务
/// </summary>
/// <param name="threadTasks"></param>
/// <returns></returns>
private IEnumerator WaitAndExecuteTasks(IThreadTask[] threadTasks)
{
yield return new WaitForEndOfFrame();
for (int i = 0; i < threadTasks.Length; i++)
{
threadTasks[i].ExecuteTask();
if (threadTaskFinishHandler != null)
threadTaskFinishHandler(threadTasks[i]);
}
isBusy = false;
if (threadPoolSchedulerHandler != null)
threadPoolSchedulerHandler(threadTasks);
}
/// <summary>
/// 停止所有的异步线程任务
/// </summary>
public void AbortAsyncThreads()
{
if (!providerThreadBusy)
return;
isAborted = true;
StopCoroutine("WaitForCompletion");
if (asyncThreadTaskData != null && asyncThreadTaskData.threadTaskInfos != null)
{
lock (asyncThreadTaskData.threadTaskInfos)
{
foreach (ThreadTaskInfo threadTaskInfo in asyncThreadTaskData.threadTaskInfos)
{
if (threadTaskInfo.Running && !threadTaskInfo.Finished)
{
threadTaskInfo.threadTask.AbortTask();
}
}
}
}
if (providerThread != null && providerThread.IsAlive)
{
providerThread.Interrupt();
providerThread.Join();
}
providerThreadBusy = false;
}
void OnApplicationQuit()
{
AbortAsyncThreads();
}
void OnDestroy()
{
AbortAsyncThreads();
}
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/*
* Author:W
* 多线程任务加载器
*/
namespace W.GameFramework.MultiThread
{
/// <summary>
/// 多线程执行的所有实际任务都执行完成的回调
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="taskArr"></param>
public delegate void MultiThreadedTaskComplete<T>(T[] taskArr);
/// <summary>
/// 该线程任务内的所有实际任务执行完成的回调
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="taskArr"></param>
/// <param name="firstIndex"></param>
/// <param name="lastIndex"></param>
public delegate void MultiThreadedTaskDataComplete<T>(T[] taskArr, int firstIndex, int lastIndex);
/// <summary>
/// 执行的线程任务数据封装
/// </summary>
/// <typeparam name="T"></typeparam>
public class ThreadTaskData<T>
{
public MultiThreadedTaskComplete<T> onTaskComplete;
public MultiThreadedTaskDataComplete<T> onTaskDataComplete;
/// <summary>
/// 实际的任务集合
/// </summary>
public T[] taskArr;
/// <summary>
/// 将上述任务“划分后”的线程任务批次数组
/// </summary>
public ThreadTask<T>[] threadTaskArr;
/// <summary>
/// 所有实际任务执行完成的回调
/// </summary>
/// <param name="threadTasks"></param>
public void onTaskCompleteHandler(IThreadTask[] threadTasks)
{
if (onTaskComplete != null)
onTaskComplete(taskArr);
}
/// <summary>
/// 当前的“划分后”的线程任务内的实际任务执行完成的回调
/// </summary>
/// <param name="threadTask"></param>
public void onTaskDataCompleteHandler(IThreadTask threadTask)
{
ThreadTask<T> threadTask1 = (ThreadTask<T>)threadTask;
if (threadTask1 != null)
onTaskDataComplete(threadTask1.taskArr,threadTask1.startIndex,threadTask1.endIndex-1);
}
}
/// <summary>
/// 线程任务执行器
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="task"></param>
public delegate void ThreadTaskExecutor<T>(T task);
/// <summary>
/// 线程任务执行器
/// 【带任务索引】
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="task"></param>
/// <param name="taskIndex"></param>
public delegate void ThreadTaskExecutorIndexed<T>(T task, int taskIndex);
/// <summary>
/// 线程任务执行器
/// 【带任务参数】
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="task"></param>
/// <param name="arg"></param>
public delegate void ThreadTaskExecutorArg<T>(T task, object arg);
/// <summary>
/// 线程任务执行器
/// 【既带任务索引也带任务参数】
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="task"></param>
/// <param name="taskIndex"></param>
/// <param name="arg"></param>
public delegate void ThreadTaskExecutorArgIndexed<T>(T task, int taskIndex, object arg);
/// <summary>
/// 线程任务单元接口实现
/// </summary>
/// <typeparam name="T"></typeparam>
public class ThreadTask<T> : IThreadTask
{
/// <summary>
/// 线程任务单元批次ID
/// </summary>
public int ID;
//线程任务回调类型
public ThreadTaskExecutor<T> taskExecutor;
public ThreadTaskExecutorIndexed<T> taskExecutorIndexed;
public ThreadTaskExecutorArg<T> taskExecutorArg;
public ThreadTaskExecutorArgIndexed<T> threadTaskExecutorArgIndexed;
/// <summary>
/// 该线程任务单元处理的实际任务集的开始的索引
/// </summary>
public int startIndex;
/// <summary>
/// 该线程任务单元处理的实际任务集的结束的索引
/// </summary>
public int endIndex;
/// <summary>
/// 实际任务集
/// </summary>
public T[] taskArr;
public object arg;
public bool isAborted = false;
public ThreadTask(ThreadTaskExecutor<T> taskExecutor,T[] taskArr,int startIndex,int endIndex)
{
this.taskExecutor = taskExecutor;
this.taskArr = taskArr;
this.startIndex = startIndex;
this.endIndex = endIndex;
}
public ThreadTask(ThreadTaskExecutorIndexed<T> taskExecutorIndexed, T[] taskArr, int startIndex, int endIndex)
{
this.taskExecutorIndexed = taskExecutorIndexed;
this.taskArr = taskArr;
this.startIndex = startIndex;
this.endIndex = endIndex;
}
public ThreadTask(ThreadTaskExecutorArg<T> taskExecutorArg, T[] taskArr, object arg, int startIndex, int endIndex)
{
this.taskExecutorArg = taskExecutorArg;
this.taskArr = taskArr;
this.startIndex = startIndex;
this.endIndex = endIndex;
this.arg = arg;
}
public ThreadTask(ThreadTaskExecutorArgIndexed<T> threadTaskExecutorArgIndexed, T[] taskArr, object arg, int startIndex, int endIndex)
{
this.threadTaskExecutorArgIndexed = threadTaskExecutorArgIndexed;
this.taskArr = taskArr;
this.startIndex = startIndex;
this.endIndex = endIndex;
this.arg = arg;
}
/// <summary>
/// 停止任务
/// </summary>
public void AbortTask()
{
isAborted = true;
}
/// <summary>
/// 执行任务
/// </summary>
public void ExecuteTask()
{
if (taskArr == null || taskArr.Length == 0)
return;
if (taskExecutor != null)
{
for (int i = startIndex; i < endIndex && !isAborted; i++)
{
ThreadManager.Instance.SleepOrAbortIfUnityInactive();
taskExecutor(taskArr[i]);
}
}
if (taskExecutorIndexed != null)
{
for (int i = startIndex; i < endIndex && !isAborted; i++)
{
ThreadManager.Instance.SleepOrAbortIfUnityInactive();
taskExecutorIndexed(taskArr[i],i);
}
}
if (taskExecutorArg != null)
{
for (int i = startIndex; i < endIndex && !isAborted; i++)
{
ThreadManager.Instance.SleepOrAbortIfUnityInactive();
taskExecutorArg(taskArr[i],arg);
}
}
if (threadTaskExecutorArgIndexed != null)
{
for (int i = startIndex; i < endIndex && !isAborted; i++)
{
ThreadManager.Instance.SleepOrAbortIfUnityInactive();
threadTaskExecutorArgIndexed(taskArr[i],i,arg);
}
}
}
}
/// <summary>
/// 多线程任务处理
/// </summary>
public static class MultiThreadedTaskLoadHelper
{
/// <summary>
/// 多任务异步处理
/// 1.使用协程处理
/// 2.使用线程池处理
/// </summary>
/// <typeparam name="D">任务执行器类型</typeparam>
/// <typeparam name="T">任务类型</typeparam>
/// <param name="executor">任务执行器</param>
/// <param name="taskArr">任务数组</param>
/// <param name="arg">任务参数</param>
/// <param name="onCompelte">所有任务完成回调</param>
/// <param name="onTaskDataComplete">当前线程任务完成回调</param>
/// <param name="maxThreads">最大线程数</param>
/// <param name="ForceToMainThread">是否强制使用主线程的协程来执行</param>
/// <returns></returns>
public static ThreadPoolHelper DealMultiThreadTaskLoadExcution<D, T>(D executor,T[] taskArr,object arg,
MultiThreadedTaskComplete<T> onCompelte,MultiThreadedTaskDataComplete<T> onTaskDataComplete,
int maxThreads = -1, ThreadPoolHelper threadPoolHelper = null, bool ForceToMainThread = false)
{
if(threadPoolHelper == null)
threadPoolHelper = ThreadManager.Instance.CreateThreadPoolHelper();
threadPoolHelper.ForceToMainThread = ForceToMainThread;
if (maxThreads <= 0)
maxThreads = Mathf.Max(SystemInfo.processorCount - 1, 1);
//计算每个线程可以处理的任务数
int tasksPerThread = 1;
if (maxThreads > 1)
tasksPerThread = 2;
//计算应该新建的线程任务数量
int threadTaskNum = Mathf.Min(maxThreads*tasksPerThread,taskArr.Length);
Debug.Log("多任务线程实际的任务数:"+taskArr.Length+" 划分成的线程任务数:"+threadTaskNum);
//计算每个线程任务,预计能分配到的实际任务数
int objectsPerThreadTask = (int)Mathf.Ceil((float)taskArr.Length/(float)threadTaskNum);
ThreadTask<T>[] threadTaskArr = new ThreadTask<T>[threadTaskNum];
Type delegateType = typeof(D);
int count = 0;
for (int i = 0; i < threadTaskNum; i++)
{
//计算每个线程任务,实际分配的实际任务数
int taskSize = Mathf.Min(taskArr.Length-count, objectsPerThreadTask);
if (delegateType == typeof(ThreadTaskExecutor<T>))
{
threadTaskArr[i] = new ThreadTask<T>((executor as ThreadTaskExecutor<T>), taskArr, count, count + taskSize);
}
else if (delegateType == typeof(ThreadTaskExecutorIndexed<T>))
{
threadTaskArr[i] = new ThreadTask<T>((executor as ThreadTaskExecutorIndexed<T>), taskArr, count, count + taskSize);
}
else if (delegateType == typeof(ThreadTaskExecutorArg<T>))
{
threadTaskArr[i] = new ThreadTask<T>((executor as ThreadTaskExecutorArg<T>), taskArr, arg, count, count + taskSize);
}
else if (delegateType == typeof(ThreadTaskExecutorArgIndexed<T>))
{
threadTaskArr[i] = new ThreadTask<T>((executor as ThreadTaskExecutorArgIndexed<T>), taskArr, arg, count, count + taskSize);
}
threadTaskArr[i].ID = i;
Debug.Log("多线程任务划分批次 ID:" + i + " startIndex="+count+" endIndex="+(count+taskSize-1));
count += objectsPerThreadTask;
}
ThreadTaskData<T> taskData = new ThreadTaskData<T>();
taskData.taskArr = taskArr;
taskData.onTaskComplete = onCompelte;
taskData.onTaskDataComplete = onTaskDataComplete;
taskData.threadTaskArr = threadTaskArr;
threadPoolHelper.DealTaskByAsyncThreads(threadTaskArr,taskData.onTaskCompleteHandler,taskData.onTaskDataCompleteHandler,maxThreads);
return threadPoolHelper;
}
}
}