(小白)unity多线程的学习:Loom-ThreadPoolScheduler类
来源:互联网 发布:淘宝店铺装修设计教程 编辑:程序博客网 时间:2024/05/29 16:25
using System;
using System.Collections;
using System.Threading;
using System.Collections.Generic;
using UnityEngine;
using Frankfort.Threading.Internal;
//C# sharp
namespace Frankfort.Threading
{
//声明委托对象
public delegate void ThreadPoolSchedulerEvent(IThreadWorkerObject[] finishedObjects);
public delegate void ThreadedWorkCompleteEvent(IThreadWorkerObject finishedObject);
/// <summary>
/// This is the most important class of the framework. It starts & stops threads, caps the amount of threads running at the same time, handles Mainthread completion-delegates, etc.
/// 最重要的类,能够开启/停止线程,抓取同时运行的线程数,处理主线程委托机制
/// </summary>
public class ThreadPoolScheduler : MonoBehaviour
{
//--------------- public Session Variables 公有变量--------------------
public bool DebugMode = false;//调试模式
public bool ForceToMainThread = false;//是否将加入主线程
public float WaitForSecondsTime = 0.001f; //等待时间
//忙碌判断
public bool isBusy
{
get
{
return _shedularBusy;
}
}
//?
public float Progress
{
get
{
if (workData == null || workData.workerPackages == null || workData.workerPackages.Length == 0)
return 1f;
//return (float)GetHandledFinishedPackages().Length / (float)workData.workerPackages.Length;
int finishedPackages = 0;
int i = workData.workerPackages.Length;
while(--i > -1)
{
if (workData.workerPackages[i].finishedWorking)
finishedPackages++;
}
return (float)finishedPackages / (float)workData.workerPackages.Length;
}
}
//--------------- public Session Variables --------------------
//--------------- PrivateSession Variables 私有变量--------------------
private bool _providerThreadBusy;//线程提供者忙碌状态
private bool _shedularBusy;//调度器忙碌状态
private bool _isAborted;//是否中止
private ASyncThreadWorkData workData;//工作数据
private Thread providerThread;//线程提供者
private int workObjectIndex;//工作对象索引
private ThreadPoolSchedulerEvent onCompleteCallBack;//线程池调度器事件 对象
private ThreadedWorkCompleteEvent onWorkerObjectDoneCallBack;//线程工作完成事件 对象
private bool safeMode;//安全模式
//--------------- Private Session Variables --------------------
//--------------------------------------- UNITY MONOBEHAVIOUR COMMANDS Unity方面控制--------------------------------------
//--------------------------------------- UNITY MONOBEHAVIOUR COMMANDS --------------------------------------
#region UNITY MONOBEHAVIOUR COMMANDS
//初始化
protected virtual void Awake()
{
MainThreadWatchdog.Init();//初始化 主线程监测器
MainThreadDispatcher.Init();//初始化 主线程调度员
UnityActivityWatchdog.Init();//初始化 Unity活动监测器
}
//应用是否退出
protected virtual void OnApplicationQuit()
{
Debug.Log("ThreadPoolScheduler.OnApplicationQuit!");
AbortASyncThreads();
}
//销毁
protected virtual void OnDestroy()
{
Debug.Log("ThreadPoolScheduler.OnDestroy!");
AbortASyncThreads();//调用同一个方法,但原因不一样
}
#endregion
//--------------------------------------- UNITY MONOBEHAVIOUR COMMANDS --------------------------------------
//--------------------------------------- UNITY MONOBEHAVIOUR COMMANDS --------------------------------------
//--------------------------------------- UNITY COROUTINE & PROVIDER-THREAD IMPLEMENTATION Unity协程 和 线程提供者 完善--------------------------------------
//--------------------------------------- UNITY COROUTINE & PROVIDER-THREAD IMPLEMENTATION --------------------------------------
#region UNITY COROUTINE & PROVIDER-THREAD IMPLEMENTATION
/// <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 IThreadWorkerObject's 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 IThreadWorkerObject's 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>
public void StartASyncThreads(IThreadWorkerObject[] workerObjects, ThreadPoolSchedulerEvent onCompleteCallBack, ThreadedWorkCompleteEvent onPackageExecuted = null, int maxThreads = -1, bool safeMode = true)
{
if (_shedularBusy)//若调度器忙碌
{
Debug.LogError("You are trying to start a new ASync threading-process, but is still Busy!");
return;
}
if (workerObjects == null || workerObjects.Length == 0)//若工作对象数组为0或空
{
Debug.LogError("Please provide an Array with atleast \"IThreadWorkerObject\"-object!");
return;
}
//设置相关字段
_isAborted = false;//
_shedularBusy = true;
_providerThreadBusy = true;
this.onCompleteCallBack = onCompleteCallBack;
this.onWorkerObjectDoneCallBack = onPackageExecuted;
if (!ForceToMainThread)
{
//--------------- Start Waiting for the Provider-thread to complete --------------------
StartCoroutine("WaitForCompletion");
workData = new ASyncThreadWorkData(workerObjects, safeMode, maxThreads);
providerThread = new Thread(new ThreadStart(InvokeASyncThreadPoolWork));
providerThread.Start();
//--------------- Start Waiting for the Provider-thread to complete --------------------
}
else
{
//--------------- Execute all work in one bunch! --------------------
StartCoroutine(WaitAndExecuteWorkerObjects(workerObjects));
//--------------- Execute all work in one bunch! --------------------
}
}
private IEnumerator WaitAndExecuteWorkerObjects(IThreadWorkerObject[] workerObjects)
{
yield return new WaitForEndOfFrame();
for (int i = 0; i < workerObjects.Length; i++)
{
workerObjects[i].ExecuteThreadedWork();
if (onWorkerObjectDoneCallBack != null)
onWorkerObjectDoneCallBack(workerObjects[i]);
}
_shedularBusy = false;
_providerThreadBusy = false;
if (onCompleteCallBack != null)
onCompleteCallBack(workerObjects);
}
private IEnumerator WaitForCompletion()
{
if (DebugMode)
Debug.Log(" ----- WaitForCompletion: " + Thread.CurrentThread.ManagedThreadId);
while (!_isAborted)
{
//After waiting a while, in the meantime it might have finished itself, or got aborted!
yield return new WaitForSeconds(WaitForSecondsTime);
if(_isAborted)
break;
//--------------- fire events while still working --------------------
int finishedObjectsCount = GetFinishedPackagesCount();
if (finishedObjectsCount == workData.workerPackages.Length)
break;
int unhandledPackagesCount = GetUnhandledFinishedPackagesCount();
if (DebugMode)
Debug.Log(" ----- unhandledPackages: " + unhandledPackagesCount + " ( out of: " + finishedObjectsCount + " completed so far...)");
if (unhandledPackagesCount > 0)
{
foreach (ThreadWorkStatePackage package in workData.workerPackages)
{
if (package.finishedWorking && !package.eventFired)
{
if (onWorkerObjectDoneCallBack != null)
onWorkerObjectDoneCallBack(package.workerObject);
package.eventFired = true;
}
}
}
//--------------- fire events while still working --------------------
}
if(!_isAborted)
{
if (DebugMode)
Debug.Log(" ----- Coroutine knows its done!");
IThreadWorkerObject[] workedObjects = GetWorkerObjectsFromPackages();
workData.Dispose();
workData = null;
_shedularBusy = false;
if (onCompleteCallBack != null)
onCompleteCallBack(workedObjects);
}
}
#endregion
//--------------------------------------- UNITY COROUTINE & PROVIDER-THREAD IMPLEMENTATION --------------------------------------
//--------------------------------------- UNITY COROUTINE & PROVIDER-THREAD IMPLEMENTATION --------------------------------------
//--------------------------------------- EXTRA COMMANDS & ACTIONS 额外控制 和 响应动作 --------------------------------------
//--------------------------------------- EXTRA COMMANDS & ACTIONS --------------------------------------
#region EXTRA COMMANDS & ACTIONS
/// <summary>
/// Aborts all worker processes currently queued.
/// 停止当前所有进程队列
/// </summary>
/// <param name="sleepTillAborted">if true: Makes sure that after invoking "AbortASyncThreads" the ThreadPoolSheduler is available again, but halts the MainThread while waiting for the other threads to finish</param>
public void AbortASyncThreads()
{
if (!_providerThreadBusy)
return;
_isAborted = true;
StopCoroutine("WaitForCompletion");
if(workData != null && workData.workerPackages != null)
{
lock (workData.workerPackages)
{
foreach (ThreadWorkStatePackage package in workData.workerPackages)
{
if (package.running && !package.finishedWorking)
package.workerObject.AbortThreadedWork();
}
}
}
if (providerThread != null && providerThread.IsAlive)
{
Debug.Log("ThreadPoolScheduler.AbortASyncThreads - Interrupt!");
providerThread.Interrupt();
providerThread.Join();
}
else
{
Debug.Log("ThreadPoolScheduler.AbortASyncThreads!");
}
_providerThreadBusy = false;
}
#endregion
//--------------------------------------- EXTRA COMMANDS & ACTIONS --------------------------------------
//--------------------------------------- EXTRA COMMANDS & ACTIONS --------------------------------------
//--------------------------------------- .NET THREADPOOL IMPLEMENTATION 实施线程池--------------------------------------
//--------------------------------------- .NET THREADPOOL IMPLEMENTATION --------------------------------------
#region .NET THREADPOOL IMPLEMENTATION
/// <summary>
/// This method is the work-provider-method. It makes sure the .NET threadpool has things to do...
/// 供应者相关方法:确保线程池不空
/// This method is NOT invoked by the mainThread, therefor is safe to use WaitHandle.WaitAll / WaitAny without halting Unity's gameThread!
/// 此方法不由主线程调用,因此即使使用wait也不影响Unity的游戏线程
/// 唤醒AsyncThreadPoolWork
/// </summary>
public void InvokeASyncThreadPoolWork()
{
UnityActivityWatchdog.SleepOrAbortIfUnityInactive();
int totalWork = workData.workerPackages.Length;
int startBurst = Mathf.Clamp(workData.maxWorkingThreads, 1, totalWork);
if (DebugMode)
Debug.Log(" ----- InvokeASyncThreadPoolWork. startBurst: " + startBurst + ", totalWork: " + totalWork);
//--------------- Initial Startup burst --------------------
for (int i = 0; i < startBurst && !_isAborted; i++)
{
//Add to .NET ThreadPool
if (workData.workerPackages[i] != null)
{
workData.workerPackages[i].started = true;
ThreadPool.QueueUserWorkItem(workData.workerPackages[i].ExecuteThreadWork, i);
}
}
//--------------- Initial Startup burst ---------------s-----
if (DebugMode)
Debug.Log(" ----- Burst with WorkerObjects being processed!");
//--------------- Create a new Thread to keep the Threadpool running & cores saturated! --------------------
//创建一个新线程保持线程池运行 和 饱和??
workObjectIndex = startBurst; //at this point the amount of running WorkObjects/Threads is equal to the startBurst;
while (workObjectIndex < totalWork && !_isAborted)
{
UnityActivityWatchdog.SleepOrAbortIfUnityInactive();
AutoResetEvent[] startedEvents = GetStartedPackageEvents();
if (startedEvents.Length > 0)
WaitHandle.WaitAny(startedEvents);
workData.workerPackages[workObjectIndex].started = true;
ThreadPool.QueueUserWorkItem(workData.workerPackages[workObjectIndex].ExecuteThreadWork, workObjectIndex);
workObjectIndex++;
}
//--------------- Create a new Thread to keep the Threadpool running & cores saturated! --------------------
if (DebugMode)
Debug.Log(" ----- all packages fed to the pool!");
//--------------- Wait till all are finished! --------------------
//All WorkObjects have been set to work, but the last few Threads might still be pending!
AutoResetEvent[] pendingEvents = GetStartedPackageEvents();
if (pendingEvents.Length > 0)
{
UnityActivityWatchdog.SleepOrAbortIfUnityInactive();
WaitHandle.WaitAll(pendingEvents);
}
//--------------- Wait till all are finished! --------------------
if (DebugMode)
Debug.Log(" ----- PROVIDER THREAD DONE");
//DONE!
_providerThreadBusy = false;
}
#endregion
//--------------------------------------- .NET THREADPOOL IMPLEMENTATION --------------------------------------
//--------------------------------------- .NET THREADPOOL IMPLEMENTATION --------------------------------------
//--------------------------------------- MISC 其他指令方法--------------------------------------
//--------------------------------------- MISC --------------------------------------
#region MISC
private AutoResetEvent[] GetStartedPackageEvents()
{
List<AutoResetEvent> result = new List<AutoResetEvent>();
for (int i = 0; i < workData.workerPackages.Length; i++)
{
ThreadWorkStatePackage package = workData.workerPackages[i];
if(package.started && !package.finishedWorking)
result.Add(package.waitHandle);
}
return result.ToArray();
}
private IThreadWorkerObject[] GetWorkerObjectsFromPackages()
{
if (workData == null || workData.workerPackages == null)
return new IThreadWorkerObject[0];
IThreadWorkerObject[] result = new IThreadWorkerObject[workData.workerPackages.Length];
int i = workData.workerPackages.Length;
while (--i > -1)
result[i] = workData.workerPackages[i].workerObject;
return result;
}
public int GetFinishedPackagesCount()
{
if (workData == null || workData.workerPackages == null)
return 0;
int count = 0;
int i = workData.workerPackages.Length;
while (--i > -1)
{
if (workData.workerPackages[i].finishedWorking)
count++;
}
return count;
}
public int GetUnhandledFinishedPackagesCount()
{
if (workData == null || workData.workerPackages == null)
return 0;
int count = 0;
int i = workData.workerPackages.Length;
while (--i > -1)
{
if (workData.workerPackages[i].finishedWorking && !workData.workerPackages[i].eventFired)
count++;
}
return count;
}
#endregion
//--------------------------------------- MISC --------------------------------------
//--------------------------------------- MISC --------------------------------------
}
}
0 0
- (小白)unity多线程的学习:Loom-ThreadPoolScheduler类
- unity多线程的学习-Loom-Loom类
- unity多线程的学习:Loom-IThreadWorkerObject部分
- Unity-Loom的多线程研究及优化
- Unity中使用Loom工具,Unity多线程学习
- Unity多线程(Thread)和主线程(MainThread)交互使用类——Loom工具分享
- Unity多线程(Thread)和主线程(MainThread)交互使用类——Loom工具分享
- Unity多线程(Thread)和主线程(MainThread)交互使用类——Loom工具分享
- Unity多线程(Thread)和主线程(MainThread)交互使用类——Loom工具分享
- Unity多线程(Thread)和主线程(MainThread)交互使用类——Loom工具分享
- Unity多线程(Thread)和主线程(MainThread)交互使用类——Loom工具分享
- Unity多线程(Thread)和主线程(MainThread)交互使用类——Loom工具分享
- Unity多线程(Thread)和主线程(MainThread)交互使用类——Loom工具分享
- Unity多线程(Thread)和主线程(MainThread)交互使用类——Loom工具分享
- Unity多线程(Thread)和主线程(MainThread)交互使用类——Loom工具分享
- Unity多线程(Thread)和主线程(MainThread)交互使用类——Loom工具分享
- unity+Loom实现多线程(Thread)和主线程(MainThread)交互
- unity 线程库 Loom 的初步使用
- Atitit ati licenseService 设计原理
- Python学习--装饰器
- Atitit.atiagent agent分销系统 代理系统 设计文档
- 2016-09-06 预测的艺术
- SSH整合开发实例:用户管理系统
- (小白)unity多线程的学习:Loom-ThreadPoolScheduler类
- CGRectInset,CGRectOffset,UIEdgeInsetsInsetRect的使用说明
- spring mvc date封装与数字格式化
- 实验楼Linux学习笔记(七)之帮助命令
- Atitit.异常处理 嵌套 冗长的解决方案
- 多种多样的meta标签
- 求职岗位
- Seven Puzzle AOJ 0121宽度优先搜索
- String Data JPA使用总结