using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using UnityEngine;
public class LoomTask
{
public ActionAction
{
get; set;
}
public object Data
{
get; set;
}
}
///
/// Unity主线程和开启的分线程相互之间的交互类
///
public class Loom : MonoBehaviour
{
public static int maxThreads =20;
private static int numThreads;
private static Loomcurrent;
private static bool initialized;
private readonly ListcurrentDelayed =new List();
private readonly Listdelayed =new List();
private readonly Listtasks =new List();
private readonly ListcurrentTasks =new List();
///
/// 事件队列
///
private readonly QueuequeueActions =new Queue();
///
/// 分帧加载的阈值,暂时定位30帧(每帧耗时32ms)
///
private const double oneFrameTime =32.0f;
///
/// 当前事件耗时
///
private double curTime = 0;
///
/// 计时器
///
private System.Diagnostics.Stopwatchst =new System.Diagnostics.Stopwatch();
public static LoomCurrent
{
get
{
Initialize();
return current;
}
}
private void Awake()
{
current =this;
initialized =true;
}
private static void Initialize()
{
if (!initialized)
{
if (!Application.isPlaying)
return;
initialized =true;
var g =new GameObject("Loom");
current = g.AddComponent();
}
}
///
/// 子线程逻辑放入主线程(ui相关放在unity子线程会报错)
///
/// <param name="action">逻辑
/// <param name="time">延迟执行时间
public static void QueueOnMainThread(Action action, float time =0)
{
if (time !=0)
{
lock (Current.delayed)
{
Current.delayed.Add(new DelayedQueueItem {time = Time.time + time, action = action });
}
}
else
{
lock (Current.queueActions)
{
Current.queueActions.Enqueue(action);
}
}
}
public static void QueueOnMainThread(LoomTask task)
{
lock (Current.tasks)
{
Current.tasks.Add(task);
}
}
public static void RunAsync(Action a)
{
Initialize();
while (numThreads >=maxThreads)
{
Thread.Sleep(1);
}
Interlocked.Increment(ref numThreads);
ThreadPool.QueueUserWorkItem(RunAction, a);
}
private static void RunAction(object action)
{
try
{
((Action)action)();
}
finally
{
Interlocked.Decrement(ref numThreads);
}
}
private void OnDisable()
{
if (current == this)
{
current =null;
}
}
private void Update()
{
ExcuteQueueActions();
lock (tasks)
{
currentTasks.Clear();
currentTasks.AddRange(tasks);
tasks.Clear();
}
foreach (LoomTask taskin currentTasks)
{
task.Action(task.Data);
}
lock (delayed)
{
currentDelayed.Clear();
currentDelayed.AddRange(delayed.Where(d => d.time <= Time.time));
foreach (var itemin currentDelayed)
delayed.Remove(item);
}
foreach (var vin currentDelayed)
{
try
{
v.action();
}
catch
{
VRLogger.LogError("[Loom]: task error.");
}
}
}
///
/// 执行队列事件
///
private void ExcuteQueueActions()
{
lock (queueActions)
{
curTime =0;
st.Stop();
st.Reset();
while (queueActions.Count >0 &&curTime
{
Action a =queueActions.Dequeue();
try
{
st.Start();
a?.Invoke();
curTime +=st.Elapsed.TotalMilliseconds;
st.Stop();
st.Reset();
}
catch (Exception e)
{
#if UNITY_EDITOR
VRLogger.LogError(e.Message);
#else
VRLogger.LogError(e.Message);
VRLogger.LogError(a.Target + " action error");
VRLogger.LogError(a.Method + " action error");
VRLogger.LogDebug("[Loom]:Update error stacktrace " + e.StackTrace);
#endif
}
}
}
}
public struct DelayedQueueItem
{
public float time;
public Actionaction;
}
}