Unity 已可使用 Thread、Task 等处理多线程任务,但缺少成熟的多线程任务队列工具,所以在此实现一个,代码已上传 Git 项目 GRUnityTools,可直接下载源码或通过 UPM 使用
实现目标串行与并发队列
队列是首要实现目标,且需要串行与并发两种队列,以覆盖不同需求
2. 同步与异步执行
因任务队列过多可能阻塞主线程,所以除同步执行外还需要多线程异步操作
3. 主线程同步
因为有多线程,但 Unity 部分操作只能在主线程执行,所以还需要线程同步到主线程
实现方式Task
Task 为当前 .Net 提供的实用性最高的多线程接口,可实现任务的监控与操纵
2. TaskScheduler
Task 专用调度器,可更便捷地实现 Task 队列调度
3. Loom
Loom 为网络上广为流传的 Unity 中调用主线程的工具类,目前找不到源码最原始地址,代码拷贝自知乎
实现过程
方案选择
最初即决定使用 Task 作为队列基本单位,但完全没有考虑 TaskScheduler。原计划手动实现一个调度器,负责保存传入的 Task 放入队列,可设置同步异步,根据设置实现对队列的不同操作。后来再研究微软官方文档时发现在其 Task 文档的示例中有一个 LimitedConcurrencyLevelTaskScheduler 的演示代码,直接通过 TaskScheduler 实现了可控并发数量的调度器,且当设置并发数为1时队列中的任务会逐一按顺序执行即产生了串行队列效果
TaskScheduler 有两种使用方式
方式一:为 TaskFactory 配置 TaskScheduler,通过 TaksFactory 使用配置的调度器启动 Task
//创建并发数32的调度器LimitedConcurrencyLevelTaskScheduler scheduler = new LimitedConcurrencyLevelTaskScheduler(32);
//方式1TaskFactory factory = new TaskFactory(scheduler);
factory.StartNew(()=>{
//执行任务});
方式二:直接使用 Task.Start(TaskFactory) 方法
//创建并发数1的调度器(此时即为串行队列效果)LimitedConcurrencyLevelTaskScheduler scheduler = new LimitedConcurrencyLevelTaskScheduler(1);
//声明一个 Task 对象Task task = new Task(()=>{
//任务});
//启动 Task 指定调度器task.Start(scheduler);
编写源码
创建名为 TaskQueue 的类,添加变量
//根据需求设置默认并发数private const int DefaultConcurrentCount = 32;
//线程锁private static object _lock = new object();
//默认静态串行队列对象private static TaskQueue _defaultSerial;
//默认静态并发队列对象private static TaskQueue _defaultConcurrent;
//持有的调度器private LimitedConcurrencyLevelTaskScheduler _scheduler;
//提供默认串行队列public static TaskQueue DefaultSerailQueue
{
get
{
if (_defaultSerial == null)
{
lock (_lock)
{
if (_defaultSerial == null)
{
_defaultSerial = new TaskQueue(1);
}
}
}
return _defaultSerial;
}
}
//提供默认并发队列public static TaskQueue DefaultConcurrentQueue
{
get
{
if (_defaultConcurrent == null)
{
lock (_lock)
{
if (_defaultConcurrent == null)
{
_defaultConcurrent = new TaskQueue(DefaultConcurrentCount);
}
}
}
return _defaultConcurrent;
}