Unity-Loomのマルチスレッド研究と最適化
7805 ワード
1.Loomの原理
LoomはMonoBehaviourから継承され、Unityプロセス管理におけるUpdateメソッドの下でコールバックが必要なActionをチェックしてロックとコールバックを行い、メインスレッドで実行されることを確保し、コールバックシーケンス自体が静的データとして保存され、任意のスレッド呼び出しで追加され、簡単で軽量である
2.初期化最適化
原版Loomの初期化方法は煩雑で、各シーンを初期化する必要がありますが、実際にはUnityの非破壊方法を使用してLoomを永久物体として保存することができます.このように、初期化時のメインスレッドで
LoomはMonoBehaviourから継承され、Unityプロセス管理におけるUpdateメソッドの下でコールバックが必要なActionをチェックしてロックとコールバックを行い、メインスレッドで実行されることを確保し、コールバックシーケンス自体が静的データとして保存され、任意のスレッド呼び出しで追加され、簡単で軽量である
2.初期化最適化
原版Loomの初期化方法は煩雑で、各シーンを初期化する必要がありますが、実際にはUnityの非破壊方法を使用してLoomを永久物体として保存することができます.このように、初期化時のメインスレッドで
Loom.Initialize();
を1回呼び出した後、任意のシーンの任意のスレッドでLoom.QueueOnMainThread(()=>{
});
を呼び出してメインスレッドの動作を完了させるだけでよい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;
public static Loom Current
{
get
{
Initialize();
return _current;
}
}
//#### Awake
// void Awake()
// {
// _current = this;
// initialized = true;
// }
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();
}
}
}