1.Loom原理
Loom继承自MonoBehaviour,在Unity生命周期管理中Update方法下检查需要回调的Action进行加锁并回调,确保在主线程执行,回调序列本身又作为静态数据保存,在任意线程调用添加,简单轻量
2.初始化优化
原版Loom的初始化方法较为繁琐,每个场景都需要进行初始化,其实可以使用Unity的永不销毁方法来将Loom作为一个永久物体保存下来。
因此,只需在游戏初始化场景的的主线程中调用如下方法一次即可:
Loom.Initialize();
然后在任意场景任意线程均可调用
Loom.QueueOnMainThread(()=>{
//Todo
});
来完成主线程的操作
改进版Loom源码:
using UnityEngine;
using
System.Collections;
using
System.Collections.Generic;
using System;
using
System.Threading;
using System.Linq;
///
/// Unity线程切换工具
///
public class Loom :
MonoBehaviour
{
public static int maxThreads = 8;
static int numThreads;
private static Loom _current;
public static Loom Current
{
get
{
Initialize();
return _current;
}
}
static bool initialized;
///
/// 作为初始化方法自己调用,可在初始化场景调用一次即可
///
public static void Initialize()
{
if
(!initialized)
{
if
(!Application.isPlaying)
return;
initialized =
true;
GameObject g = new
GameObject("Loom");
DontDestroyOnLoad(g);
_current =
g.AddComponent();
}
}
private List _actions = new List();
public struct DelayedQueueItem
{
public
float time;
public
Action action;
}
private List _delayed = new List();
List _currentDelayed = new List();
public static void QueueOnMainThread(Action
action)
{
QueueOnMainThread(action, 0f);
}
public static void QueueOnMainThread(Action
action, float time)
{
if (time
!= 0)
{
if (Current !=
null)
{
lock (Current._delayed)
{
Current._delayed.Add(new DelayedQueueItem {time = Time.time + time,
action = action});
}
}
}
else
{
if (Current !=
null)
{
lock (Current._actions)
{
Current._actions.Add(action);
}
}
}
}
public static Thread RunAsync(Action
a)
{
Initialize();
while
(numThreads >= maxThreads)
{
Thread.Sleep(1);
}
Interlocked.Increment(ref numThreads);
ThreadPool.QueueUserWorkItem(RunAction, a);
return
null;
}
private static void RunAction(object
action)
{
try
{
((Action)
action)();
}
catch
{
}
finally
{
Interlocked.Decrement(ref
numThreads);
}
}
void OnDisable()
{
if
(_current == this)
{
_current = null;
}
}
// Use this for
initialization
void Start()
{
}
List _currentActions = new List();
// Update is called once per
frame
void Update()
{
lock
(_actions)
{
_currentActions.Clear();
_currentActions.AddRange(_actions);
_actions.Clear();
}
foreach
(var a in _currentActions)
{
a();
}
lock
(_delayed)
{
_currentDelayed.Clear();
_currentDelayed.AddRange(_delayed.Where(d => d.time <=
Time.time));
foreach (var item in
_currentDelayed)
_delayed.Remove(item);
}
foreach
(var delayed in _currentDelayed)
{
delayed.action();
}
}
}
未改进版Loom源码
using
UnityEngine;
using
System.Collections;
using
System.Collections.Generic;
using
System;
using
System.Threading;
using
System.Linq;
public class Loom :
MonoBehaviour
{
public static int maxThreads =
8;
static int
numThreads;
private static Loom
_current;
private int
_count;
public static Loom
Current
{
get
{
Initialize();
return
_current;
}
}
void
Awake()
{
_current =
this;
initialized =
true;
}
static bool
initialized;
static void
Initialize()
{
if
(!initialized)
{
if(!Application.isPlaying)
return;
initialized =
true;
var g = new
GameObject("Loom");
_current =
g.AddComponent();
}
}
private List _actions = new
List();
public struct
DelayedQueueItem
{
public
float time;
public
Action action;
}
private List _delayed = new
List();
List _currentDelayed = new
List();
public static void QueueOnMainThread(Action
action)
{
QueueOnMainThread( action,
0f);
}
public static void QueueOnMainThread(Action
action, float
time)
{
if(time !=
0)
{
lock(Current._delayed)
{
Current._delayed.Add(new DelayedQueueItem { time
= Time.time + time, action =
action});
}
}
else
{
lock
(Current._actions)
{
Current._actions.Add(action);
}
}
}
public static Thread RunAsync(Action
a)
{
Initialize();
while(numThreads >=
maxThreads)
{
Thread.Sleep(1);
}
Interlocked.Increment(ref
numThreads);
ThreadPool.QueueUserWorkItem(RunAction,
a);
return
null;
}
private static void RunAction(object
action)
{
try
{
((Action)action)();
}
catch
{
}
finally
{
Interlocked.Decrement(ref
numThreads);
}
}
void
OnDisable()
{
if
(_current == this)
{
_current =
null;
}
}
// Use this for
initialization
void
Start()
{
}
List _currentActions = new
List();
// Update is called once per
frame
void
Update()
{
lock
(_actions)
{
_currentActions.Clear();
_currentActions.AddRange(_actions);
_actions.Clear();
}
foreach(var a in
_currentActions)
{
a();
}
lock(_delayed)
{
_currentDelayed.Clear();
_currentDelayed.AddRange(_delayed.Where(d=>d.time <=
Time.time));
foreach(var item in
_currentDelayed)
_delayed.Remove(item);
}
foreach(var delayed in
_currentDelayed)
{
delayed.action();
}
}
}
地址:
参考资料:
加载中,请稍候......