mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-09-07 11:28:35 -05:00
rename UniTask to DepthFirstScheduler
This commit is contained in:
177
Scripts/DepthFirstScheduler/Functor.cs
Normal file
177
Scripts/DepthFirstScheduler/Functor.cs
Normal file
@@ -0,0 +1,177 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace DepthFirstScheduler
|
||||
{
|
||||
public enum ExecutionStatus
|
||||
{
|
||||
Unknown,
|
||||
Done,
|
||||
Continue, // coroutine or schedulable
|
||||
Error,
|
||||
}
|
||||
|
||||
public interface IFunctor<T>
|
||||
{
|
||||
T GetResult();
|
||||
Exception GetError();
|
||||
ExecutionStatus Execute();
|
||||
}
|
||||
|
||||
#region Functor
|
||||
public class Functor<T> : IFunctor<T>
|
||||
{
|
||||
T m_result;
|
||||
public T GetResult()
|
||||
{
|
||||
return m_result;
|
||||
}
|
||||
|
||||
Exception m_error;
|
||||
public Exception GetError()
|
||||
{
|
||||
return m_error;
|
||||
}
|
||||
|
||||
Action m_pred;
|
||||
public Functor(Func<T> func)
|
||||
{
|
||||
m_pred = () => m_result = func();
|
||||
}
|
||||
|
||||
public ExecutionStatus Execute()
|
||||
{
|
||||
try
|
||||
{
|
||||
m_pred();
|
||||
return ExecutionStatus.Done;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
m_error = ex;
|
||||
return ExecutionStatus.Error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Functor
|
||||
{
|
||||
/// <summary>
|
||||
/// 引数の型を隠蔽した実行器を生成する
|
||||
/// </summary>
|
||||
/// <typeparam name="S">引数の型</typeparam>
|
||||
/// <typeparam name="T">結果の型</typeparam>
|
||||
/// <param name="arg"></param>
|
||||
/// <param name="pred"></param>
|
||||
/// <returns></returns>
|
||||
public static Functor<T> Create<S, T>(Func<S> arg, Func<S, T> pred)
|
||||
{
|
||||
return new Functor<T>(() => pred(arg()));
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region CoroutineFunctor
|
||||
public class CoroutineFunctor<T> : IFunctor<T>
|
||||
{
|
||||
T m_result;
|
||||
public T GetResult()
|
||||
{
|
||||
return m_result;
|
||||
}
|
||||
|
||||
Exception m_error;
|
||||
public Exception GetError()
|
||||
{
|
||||
return m_error;
|
||||
}
|
||||
|
||||
Func<T> m_arg;
|
||||
Func<T, IEnumerator> m_starter;
|
||||
IEnumerator m_it;
|
||||
public CoroutineFunctor(Func<T> arg, Func<T, IEnumerator> starter)
|
||||
{
|
||||
m_arg = arg;
|
||||
m_starter = starter;
|
||||
}
|
||||
|
||||
public ExecutionStatus Execute()
|
||||
{
|
||||
if (m_it == null)
|
||||
{
|
||||
m_result = m_arg();
|
||||
m_it = m_starter(m_result);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (m_it.MoveNext())
|
||||
{
|
||||
return ExecutionStatus.Continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ExecutionStatus.Done;
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
m_error = ex;
|
||||
return ExecutionStatus.Error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class CoroutineFunctor
|
||||
{
|
||||
public static CoroutineFunctor<T> Create<T>(Func<T> arg, Func<T, IEnumerator> starter)
|
||||
{
|
||||
return new CoroutineFunctor<T>(arg, starter);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
/*
|
||||
public class SchedulableFunctor<T> : IFunctor<T>
|
||||
{
|
||||
Schedulable<T> m_schedulable;
|
||||
Func<Schedulable<T>> m_starter;
|
||||
TaskChain m_chain;
|
||||
|
||||
public SchedulableFunctor(Func<Schedulable<T>> starter)
|
||||
{
|
||||
m_starter = starter;
|
||||
}
|
||||
|
||||
public ExecutionStatus Execute()
|
||||
{
|
||||
if (m_chain == null)
|
||||
{
|
||||
m_schedulable = m_starter();
|
||||
m_chain = TaskChain.Schedule(m_schedulable, ex => m_error = ex);
|
||||
}
|
||||
|
||||
return m_chain.Next();
|
||||
}
|
||||
|
||||
Exception m_error;
|
||||
public Exception GetError()
|
||||
{
|
||||
return m_error;
|
||||
}
|
||||
|
||||
public T GetResult()
|
||||
{
|
||||
return m_schedulable.Func.GetResult();
|
||||
}
|
||||
}
|
||||
|
||||
public static class SchedulableFunctor
|
||||
{
|
||||
public static SchedulableFunctor<T> Create<T>(Func<Schedulable<T>> starter)
|
||||
{
|
||||
return new SchedulableFunctor<T>(starter);
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
12
Scripts/DepthFirstScheduler/Functor.cs.meta
Normal file
12
Scripts/DepthFirstScheduler/Functor.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c320f3f577dde634a871dc88266c2a20
|
||||
timeCreated: 1520084196
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
56
Scripts/DepthFirstScheduler/LockQueue.cs
Normal file
56
Scripts/DepthFirstScheduler/LockQueue.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
||||
namespace DepthFirstScheduler
|
||||
{
|
||||
public class LockQueue<T> where T : class
|
||||
{
|
||||
List<T> m_queue = new List<T>();
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (((ICollection)m_queue).SyncRoot)
|
||||
{
|
||||
return m_queue.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Enqueue(T t)
|
||||
{
|
||||
lock (((ICollection)m_queue).SyncRoot)
|
||||
{
|
||||
m_queue.Add(t);
|
||||
}
|
||||
}
|
||||
|
||||
public T Dequeue(out int remain)
|
||||
{
|
||||
lock (((ICollection)m_queue).SyncRoot)
|
||||
{
|
||||
if (m_queue.Count == 0)
|
||||
{
|
||||
remain = 0;
|
||||
return null;
|
||||
}
|
||||
var item = m_queue[0];
|
||||
m_queue.RemoveAt(0);
|
||||
remain = m_queue.Count;
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
public T Dequeue()
|
||||
{
|
||||
lock (((ICollection)m_queue).SyncRoot)
|
||||
{
|
||||
if (m_queue.Count == 0) return null;
|
||||
var item = m_queue[0];
|
||||
m_queue.RemoveAt(0);
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Scripts/DepthFirstScheduler/LockQueue.cs.meta
Normal file
12
Scripts/DepthFirstScheduler/LockQueue.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f6b1eb436e400704ab6e2ad6eff29f4b
|
||||
timeCreated: 1519978475
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
148
Scripts/DepthFirstScheduler/MainThreadDispatcher.cs
Normal file
148
Scripts/DepthFirstScheduler/MainThreadDispatcher.cs
Normal file
@@ -0,0 +1,148 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace DepthFirstScheduler
|
||||
{
|
||||
/// <summary>
|
||||
/// UniRxのMainThreadDispatcherを参考にした。
|
||||
/// * https://github.com/neuecc/UniRx/blob/master/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/MainThreadDispatcher.cs
|
||||
/// </summary>
|
||||
public class MainThreadDispatcher : MonoBehaviour
|
||||
{
|
||||
|
||||
[Header("Debug")]
|
||||
public int TaskCount;
|
||||
|
||||
IEnumerable<Transform> Ancestors(Transform t)
|
||||
{
|
||||
yield return t;
|
||||
|
||||
if (t.parent != null)
|
||||
{
|
||||
foreach (var x in Ancestors(t.parent))
|
||||
{
|
||||
yield return x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
TaskCount = Scheduler.MainThread.UpdateAndGetTaskCount();
|
||||
}
|
||||
|
||||
static MainThreadDispatcher instance;
|
||||
static bool initialized;
|
||||
static bool isQuitting = false;
|
||||
|
||||
public static bool IsInitialized
|
||||
{
|
||||
get { return initialized && instance != null; }
|
||||
}
|
||||
|
||||
[ThreadStatic]
|
||||
static object mainThreadToken;
|
||||
|
||||
public static MainThreadDispatcher Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
Initialize();
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
if (!initialized)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
MainThreadDispatcher dispatcher = null;
|
||||
|
||||
try
|
||||
{
|
||||
dispatcher = GameObject.FindObjectOfType<MainThreadDispatcher>();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Throw exception when calling from a worker thread.
|
||||
var ex = new Exception("UniRx requires a MainThreadDispatcher component created on the main thread. Make sure it is added to the scene before calling UniRx from a worker thread.");
|
||||
UnityEngine.Debug.LogException(ex);
|
||||
throw ex;
|
||||
}
|
||||
|
||||
if (isQuitting)
|
||||
{
|
||||
// don't create new instance after quitting
|
||||
// avoid "Some objects were not cleaned up when closing the scene find target" error.
|
||||
return;
|
||||
}
|
||||
|
||||
if (dispatcher == null)
|
||||
{
|
||||
// awake call immediately from UnityEngine
|
||||
new GameObject("MainThreadDispatcher").AddComponent<MainThreadDispatcher>();
|
||||
}
|
||||
else
|
||||
{
|
||||
dispatcher.Awake(); // force awake
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsInMainThread
|
||||
{
|
||||
get
|
||||
{
|
||||
return (mainThreadToken != null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Awake()
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
Debug.Log("Initialize UniTask.MainThredDispatcher");
|
||||
|
||||
instance = this;
|
||||
mainThreadToken = new object();
|
||||
initialized = true;
|
||||
|
||||
DontDestroyOnLoad(gameObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this != instance)
|
||||
{
|
||||
Debug.LogWarning("There is already a MainThreadDispatcher in the scene.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
if (instance == this)
|
||||
{
|
||||
instance = GameObject.FindObjectOfType<MainThreadDispatcher>();
|
||||
initialized = instance != null;
|
||||
}
|
||||
|
||||
if (Scheduler.SingleWorkerThread != null)
|
||||
{
|
||||
Scheduler.SingleWorkerThread.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
void OnApplicationQuit()
|
||||
{
|
||||
isQuitting = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Scripts/DepthFirstScheduler/MainThreadDispatcher.cs.meta
Normal file
12
Scripts/DepthFirstScheduler/MainThreadDispatcher.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b030a9507e46dd3488c080be0227b219
|
||||
timeCreated: 1519977925
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
48
Scripts/DepthFirstScheduler/MonitorQueue.cs
Normal file
48
Scripts/DepthFirstScheduler/MonitorQueue.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
|
||||
namespace DepthFirstScheduler
|
||||
{
|
||||
/// <summary>
|
||||
/// http://blogs.msdn.com/b/toub/archive/2006/04/12/blocking-queues.aspx
|
||||
///
|
||||
/// <20>I<EFBFBD><49><EFBFBD><EFBFBD><EFBFBD>ʒm<CA92><6D><EFBFBD><EFBFBD><EFBFBD>ɂ<EFBFBD>null<6C>𓊓<EFBFBD><F0938A93><EFBFBD><EFBFBD><EFBFBD><EFBFBD>肪<EFBFBD>g<EFBFBD><67><EFBFBD><EFBFBD>
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public class MonitorQueue<T>
|
||||
where T : class
|
||||
{
|
||||
private Int32 _count = 0;
|
||||
public Int32 Count
|
||||
{
|
||||
get
|
||||
{
|
||||
return _count;
|
||||
}
|
||||
}
|
||||
|
||||
private Queue<T> _queue = new Queue<T>();
|
||||
|
||||
public T Dequeue()
|
||||
{
|
||||
lock (_queue)
|
||||
{
|
||||
while (_count <= 0) Monitor.Wait(_queue);
|
||||
_count--;
|
||||
return _queue.Dequeue();
|
||||
}
|
||||
}
|
||||
|
||||
public void Enqueue(T data)
|
||||
{
|
||||
lock (_queue)
|
||||
{
|
||||
_queue.Enqueue(data);
|
||||
_count++;
|
||||
Monitor.Pulse(_queue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Scripts/DepthFirstScheduler/MonitorQueue.cs.meta
Normal file
12
Scripts/DepthFirstScheduler/MonitorQueue.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5e968e04ff53e1c4a9a2869b7cf76055
|
||||
timeCreated: 1519990411
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
243
Scripts/DepthFirstScheduler/Schedulable.cs
Normal file
243
Scripts/DepthFirstScheduler/Schedulable.cs
Normal file
@@ -0,0 +1,243 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
#if (NET_4_6 && UNITY_2017_1_OR_NEWER)
|
||||
using System.Threading.Tasks;
|
||||
#endif
|
||||
|
||||
namespace DepthFirstScheduler
|
||||
{
|
||||
public interface ISchedulable
|
||||
{
|
||||
/// <returns>実行が終了したか?Coroutineの実行が一回で終わらない場合がある</returns>
|
||||
ExecutionStatus Execute();
|
||||
Exception GetError();
|
||||
IScheduler Schedulder { get; }
|
||||
|
||||
ISchedulable Parent { get; set; }
|
||||
void AddChild(ISchedulable child);
|
||||
IEnumerable<ISchedulable> Traverse();
|
||||
}
|
||||
|
||||
public static class ISchedulableExtensions
|
||||
{
|
||||
public static ISchedulable GetRoot(this ISchedulable self)
|
||||
{
|
||||
var current = self;
|
||||
while (current.Parent != null)
|
||||
{
|
||||
current = current.Parent;
|
||||
}
|
||||
return current;
|
||||
}
|
||||
}
|
||||
|
||||
public class Schedulable<T> : ISchedulable
|
||||
{
|
||||
List<ISchedulable> m_children = new List<ISchedulable>();
|
||||
public void AddChild(ISchedulable child)
|
||||
{
|
||||
child.Parent = this;
|
||||
m_children.Add(child);
|
||||
}
|
||||
public IEnumerable<ISchedulable> Traverse()
|
||||
{
|
||||
yield return this;
|
||||
|
||||
foreach (var child in m_children)
|
||||
{
|
||||
foreach (var x in child.Traverse())
|
||||
{
|
||||
yield return x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ISchedulable Parent
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public IScheduler Schedulder
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public IFunctor<T> Func
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public Exception GetError()
|
||||
{
|
||||
return Func.GetError();
|
||||
}
|
||||
|
||||
public Schedulable()
|
||||
{
|
||||
}
|
||||
|
||||
public Schedulable(IScheduler scheduler, IFunctor<T> func)
|
||||
{
|
||||
Schedulder = scheduler;
|
||||
Func = func;
|
||||
}
|
||||
|
||||
public ExecutionStatus Execute()
|
||||
{
|
||||
if (Func == null)
|
||||
{
|
||||
return ExecutionStatus.Done;
|
||||
}
|
||||
return Func.Execute();
|
||||
}
|
||||
|
||||
public Schedulable<Unit> AddTask(IScheduler scheduler, Action pred)
|
||||
{
|
||||
return AddTask(scheduler, () => { pred(); return Unit.Default; });
|
||||
}
|
||||
|
||||
public Schedulable<U> AddTask<U>(IScheduler scheduler, Func<U> pred)
|
||||
{
|
||||
var schedulable = new Schedulable<U>(scheduler, Functor.Create(() => Unit.Default, _ => pred()));
|
||||
AddChild(schedulable);
|
||||
return schedulable;
|
||||
}
|
||||
|
||||
public Schedulable<T> AddCoroutine(IScheduler scheduler, Func<IEnumerator> starter)
|
||||
{
|
||||
var func = CoroutineFunctor.Create(() => default(T), _ => starter());
|
||||
var schedulable = new Schedulable<T>(scheduler, func);
|
||||
AddChild(schedulable);
|
||||
return schedulable;
|
||||
}
|
||||
|
||||
public Schedulable<Unit> ContinueWith(IScheduler scheduler, Action<T> pred)
|
||||
{
|
||||
return ContinueWith(scheduler, t => { pred(t); return Unit.Default; });
|
||||
}
|
||||
|
||||
public Schedulable<U> ContinueWith<U>(IScheduler scheduler, Func<T, U> pred)
|
||||
{
|
||||
Func<T> getResult = null;
|
||||
if (Func != null)
|
||||
{
|
||||
getResult = Func.GetResult;
|
||||
}
|
||||
var func = Functor.Create(getResult, pred);
|
||||
var schedulable = new Schedulable<U>(scheduler, func);
|
||||
Parent.AddChild(schedulable);
|
||||
return schedulable;
|
||||
}
|
||||
|
||||
public Schedulable<T> ContinueWithCoroutine(IScheduler scheduler, Func<IEnumerator> starter)
|
||||
{
|
||||
var func = CoroutineFunctor.Create(() => default(T), _ => starter());
|
||||
var schedulable = new Schedulable<T>(scheduler, func);
|
||||
Parent.AddChild(schedulable);
|
||||
return schedulable;
|
||||
}
|
||||
|
||||
public Schedulable<Unit> OnExecute(IScheduler scheduler, Action<Schedulable<Unit>> pred)
|
||||
{
|
||||
Func<T> getResult = null;
|
||||
if (Func != null)
|
||||
{
|
||||
getResult = Func.GetResult;
|
||||
}
|
||||
|
||||
var schedulable = new Schedulable<Unit>();
|
||||
schedulable.Func = Functor.Create(getResult, _ => { pred(schedulable); return Unit.Default; });
|
||||
Parent.AddChild(schedulable);
|
||||
return schedulable;
|
||||
}
|
||||
|
||||
/*
|
||||
public ISchedulable<U> ContinueWithNested<U>(Func<T, ISchedulable<U>> starter, IScheduler scheduler)
|
||||
{
|
||||
var func = SchedulableFunctor.Create(() => starter(Func.GetResult()));
|
||||
return new Schedulable<U>(scheduler, func, this);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
public static class Schedulable
|
||||
{
|
||||
public static Schedulable<Unit> Create()
|
||||
{
|
||||
return new Schedulable<Unit>();
|
||||
}
|
||||
}
|
||||
|
||||
public static class SchedulableExtensions
|
||||
{
|
||||
public static void Subscribe<T>(
|
||||
this Schedulable<T> schedulable,
|
||||
IScheduler scheduler,
|
||||
Action<T> onCompleted,
|
||||
Action<Exception> onError)
|
||||
{
|
||||
schedulable.ContinueWith(scheduler, onCompleted);
|
||||
TaskChain.Schedule(schedulable.GetRoot(), onError);
|
||||
}
|
||||
|
||||
#if (NET_4_6 && UNITY_2017_1_OR_NEWER)
|
||||
public static Task<T> ToTask<T>(this Schedulable<T> schedulable)
|
||||
{
|
||||
return ToTask(schedulable, Scheduler.MainThread);
|
||||
}
|
||||
|
||||
public static Task<T> ToTask<T>(this Schedulable<T> schedulable, IScheduler scheduler)
|
||||
{
|
||||
var tcs = new TaskCompletionSource<T>();
|
||||
schedulable.Subscribe(scheduler, r => tcs.TrySetResult(r), ex => tcs.TrySetException(ex));
|
||||
return tcs.Task;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
public static ISchedulable<Unit> Sequencial<T>(IEnumerable<ISchedulable<T>> schedulables, Action<T> mergePred)
|
||||
{
|
||||
var it = schedulables.GetEnumerator();
|
||||
ISchedulable<Unit> last = Schedulable.Start(null, () => Unit.Default);
|
||||
while (it.MoveNext())
|
||||
{
|
||||
var current = it.Current;
|
||||
var merger = current.ContinueWith(result =>
|
||||
{
|
||||
mergePred(result);
|
||||
return Unit.Default;
|
||||
});
|
||||
|
||||
if (last != null)
|
||||
{
|
||||
// 連結
|
||||
current.EnumParents().Last().Parent = last;
|
||||
}
|
||||
|
||||
last = merger;
|
||||
}
|
||||
|
||||
return last;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
public static ISchedulable<S> MergeCollection<S, T, U>(this ISchedulable<S> schedulable,
|
||||
Func<S, IEnumerable<T>> extractor,
|
||||
Func<S, T, U> pred,
|
||||
Action<S, U> merger,
|
||||
IScheduler scheduler = null)
|
||||
{
|
||||
return schedulable.ContinueWithNested(x =>
|
||||
{
|
||||
var schedulables = extractor(x).Select(y => Schedulable.Start(scheduler, () => pred(x, y)));
|
||||
return Sequencial(schedulables, z => merger(x, z)).ContinueWith(_ => x);
|
||||
}, scheduler);
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
12
Scripts/DepthFirstScheduler/Schedulable.cs.meta
Normal file
12
Scripts/DepthFirstScheduler/Schedulable.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 45e21e7db278f344fbaeffc4c4b82b1e
|
||||
timeCreated: 1519981307
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
9
Scripts/DepthFirstScheduler/Scheduler.cs
Normal file
9
Scripts/DepthFirstScheduler/Scheduler.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using System;
|
||||
|
||||
namespace DepthFirstScheduler
|
||||
{
|
||||
public interface IScheduler : IDisposable
|
||||
{
|
||||
void Enqueue(TaskChain item);
|
||||
}
|
||||
}
|
||||
12
Scripts/DepthFirstScheduler/Scheduler.cs.meta
Normal file
12
Scripts/DepthFirstScheduler/Scheduler.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5a160dc164df4094dbbc892055ac82ae
|
||||
timeCreated: 1520084097
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Scripts/DepthFirstScheduler/Scheduler.meta
Normal file
8
Scripts/DepthFirstScheduler/Scheduler.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0700fb042f010694782d238049678651
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
102
Scripts/DepthFirstScheduler/Scheduler/CurrentThreadScheduler.cs
Normal file
102
Scripts/DepthFirstScheduler/Scheduler/CurrentThreadScheduler.cs
Normal file
@@ -0,0 +1,102 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DepthFirstScheduler
|
||||
{
|
||||
public static partial class Scheduler
|
||||
{
|
||||
private static IScheduler currentThread;
|
||||
|
||||
public static IScheduler CurrentThread
|
||||
{
|
||||
get { return currentThread ?? (currentThread = new CurrentThreadScheduler()); }
|
||||
}
|
||||
|
||||
public class CurrentThreadScheduler : IScheduler
|
||||
{
|
||||
[ThreadStatic]
|
||||
private static Queue<TaskChain> queue;
|
||||
|
||||
private static Queue<TaskChain> GetQueue()
|
||||
{
|
||||
return queue;
|
||||
}
|
||||
|
||||
private static void SetQueue(Queue<TaskChain> newQueue)
|
||||
{
|
||||
queue = newQueue;
|
||||
}
|
||||
|
||||
public void Enqueue(TaskChain item)
|
||||
{
|
||||
var q = GetQueue();
|
||||
|
||||
if (q == null)
|
||||
{
|
||||
q = new Queue<TaskChain>(5);
|
||||
q.Enqueue(item);
|
||||
SetQueue(q);
|
||||
|
||||
try
|
||||
{
|
||||
Trampoline.Run(q);
|
||||
}
|
||||
finally
|
||||
{
|
||||
SetQueue(null);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
q.Enqueue(item);
|
||||
}
|
||||
}
|
||||
|
||||
#region IDisposable Support
|
||||
|
||||
private bool disposedValue = false;
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
var queue = GetQueue();
|
||||
if (queue != null) queue.Clear();
|
||||
SetQueue(null);
|
||||
}
|
||||
disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
static class Trampoline
|
||||
{
|
||||
public static void Run(Queue<TaskChain> queue)
|
||||
{
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
var chain = queue.Dequeue();
|
||||
|
||||
while (true)
|
||||
{
|
||||
var status = chain.Next();
|
||||
if (status != ExecutionStatus.Continue)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 21979cc7137a17d4ea8b6202381a02d0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
52
Scripts/DepthFirstScheduler/Scheduler/StepScheduler.cs
Normal file
52
Scripts/DepthFirstScheduler/Scheduler/StepScheduler.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
namespace DepthFirstScheduler
|
||||
{
|
||||
public static partial class Scheduler
|
||||
{
|
||||
private static StepScheduler mainThread;
|
||||
|
||||
public static StepScheduler MainThread
|
||||
{
|
||||
get
|
||||
{
|
||||
if (mainThread != null) return mainThread;
|
||||
mainThread = new StepScheduler();
|
||||
MainThreadDispatcher.Initialize();
|
||||
return mainThread;
|
||||
}
|
||||
}
|
||||
|
||||
public class StepScheduler : IScheduler
|
||||
{
|
||||
LockQueue<TaskChain> m_taskQueue = new LockQueue<TaskChain>();
|
||||
|
||||
public void Enqueue(TaskChain item)
|
||||
{
|
||||
m_taskQueue.Enqueue(item);
|
||||
}
|
||||
|
||||
TaskChain m_chain;
|
||||
|
||||
public int UpdateAndGetTaskCount()
|
||||
{
|
||||
if (m_chain != null)
|
||||
{
|
||||
var status = m_chain.Next();
|
||||
if (status == ExecutionStatus.Continue)
|
||||
{
|
||||
// m_item継続中
|
||||
return m_taskQueue.Count;
|
||||
}
|
||||
m_chain = null;
|
||||
}
|
||||
|
||||
int count;
|
||||
m_chain = m_taskQueue.Dequeue(out count);
|
||||
return count;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Scripts/DepthFirstScheduler/Scheduler/StepScheduler.cs.meta
Normal file
12
Scripts/DepthFirstScheduler/Scheduler/StepScheduler.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 84161938c020c37419bc79f021f849fb
|
||||
timeCreated: 1520062584
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
42
Scripts/DepthFirstScheduler/Scheduler/ThreadPoolScheduler.cs
Normal file
42
Scripts/DepthFirstScheduler/Scheduler/ThreadPoolScheduler.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
|
||||
namespace DepthFirstScheduler
|
||||
{
|
||||
public static partial class Scheduler
|
||||
{
|
||||
private static IScheduler threadPool;
|
||||
|
||||
public static IScheduler ThreadPool
|
||||
{
|
||||
get { return threadPool ?? (threadPool = new ThreadPoolScheduler()); }
|
||||
}
|
||||
|
||||
public class ThreadPoolScheduler : IScheduler
|
||||
{
|
||||
public void Enqueue(TaskChain item)
|
||||
{
|
||||
System.Threading.ThreadPool.QueueUserWorkItem(_ =>
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
var status = item.Next();
|
||||
if (status != ExecutionStatus.Continue)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d8a8d78a486bbdf4b95ae83d02b480d8
|
||||
timeCreated: 1524110819
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
101
Scripts/DepthFirstScheduler/Scheduler/ThreadScheduler.cs
Normal file
101
Scripts/DepthFirstScheduler/Scheduler/ThreadScheduler.cs
Normal file
@@ -0,0 +1,101 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace DepthFirstScheduler
|
||||
{
|
||||
public static partial class Scheduler
|
||||
{
|
||||
private static IScheduler singleWorkerThread;
|
||||
|
||||
public static IScheduler SingleWorkerThread
|
||||
{
|
||||
get { return singleWorkerThread ?? (singleWorkerThread = new ThreadScheduler()); }
|
||||
}
|
||||
|
||||
public class ThreadScheduler : IScheduler
|
||||
{
|
||||
MonitorQueue<TaskChain> m_queue = new MonitorQueue<TaskChain>();
|
||||
|
||||
Thread m_thread;
|
||||
|
||||
public ThreadScheduler()
|
||||
{
|
||||
// start worker thread
|
||||
m_thread = new Thread(new ParameterizedThreadStart(Worker));
|
||||
m_thread.Start(m_queue);
|
||||
}
|
||||
|
||||
static void Worker(Object arg)
|
||||
{
|
||||
MonitorQueue<TaskChain> queue = (MonitorQueue<TaskChain>)arg;
|
||||
while (true)
|
||||
{
|
||||
var chain = queue.Dequeue();
|
||||
if (chain == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
var status = chain.Next();
|
||||
if (status != ExecutionStatus.Continue)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// end
|
||||
}
|
||||
|
||||
public void Enqueue(TaskChain item)
|
||||
{
|
||||
m_queue.Enqueue(item);
|
||||
}
|
||||
|
||||
#region IDisposable Support
|
||||
|
||||
private bool disposedValue = false; // 重複する呼び出しを検出するには
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
// TODO: マネージ状態を破棄します (マネージ オブジェクト)。
|
||||
if (m_thread != null)
|
||||
{
|
||||
m_queue.Enqueue(null);
|
||||
m_thread.Join();
|
||||
m_thread = null;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: アンマネージ リソース (アンマネージ オブジェクト) を解放し、下のファイナライザーをオーバーライドします。
|
||||
// TODO: 大きなフィールドを null に設定します。
|
||||
|
||||
disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: 上の Dispose(bool disposing) にアンマネージ リソースを解放するコードが含まれる場合にのみ、ファイナライザーをオーバーライドします。
|
||||
// ~ThreadScheduler() {
|
||||
// // このコードを変更しないでください。クリーンアップ コードを上の Dispose(bool disposing) に記述します。
|
||||
// Dispose(false);
|
||||
// }
|
||||
|
||||
// このコードは、破棄可能なパターンを正しく実装できるように追加されました。
|
||||
public void Dispose()
|
||||
{
|
||||
// このコードを変更しないでください。クリーンアップ コードを上の Dispose(bool disposing) に記述します。
|
||||
Dispose(true);
|
||||
// TODO: 上のファイナライザーがオーバーライドされる場合は、次の行のコメントを解除してください。
|
||||
// GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8df1de98bdc0b534bbe68e8f2f8a858f
|
||||
timeCreated: 1520062592
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
91
Scripts/DepthFirstScheduler/TaskChain.cs
Normal file
91
Scripts/DepthFirstScheduler/TaskChain.cs
Normal file
@@ -0,0 +1,91 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
||||
namespace DepthFirstScheduler
|
||||
{
|
||||
public enum ChainStatus
|
||||
{
|
||||
Unknown,
|
||||
Continue,
|
||||
Done,
|
||||
Error,
|
||||
}
|
||||
|
||||
public class TaskChain
|
||||
{
|
||||
public IEnumerator<ISchedulable> Enumerator;
|
||||
public Action<Exception> OnError;
|
||||
public ChainStatus ChainStatus;
|
||||
|
||||
public static TaskChain Schedule(ISchedulable schedulable, Action<Exception> onError)
|
||||
{
|
||||
var item = new TaskChain
|
||||
{
|
||||
Enumerator = schedulable.Traverse().GetEnumerator(),
|
||||
OnError = onError
|
||||
};
|
||||
|
||||
if (item.Enumerator.MoveNext())
|
||||
{
|
||||
if (item.Enumerator.Current.Schedulder == null)
|
||||
{
|
||||
// default
|
||||
Scheduler.MainThread.Enqueue(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
item.Enumerator.Current.Schedulder.Enqueue(item);
|
||||
}
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public ExecutionStatus Next()
|
||||
{
|
||||
if (this.ChainStatus == ChainStatus.Done
|
||||
|| this.ChainStatus== ChainStatus.Error)
|
||||
{
|
||||
return ExecutionStatus.Done;
|
||||
}
|
||||
|
||||
{
|
||||
var status = Enumerator.Current.Execute();
|
||||
if (status == ExecutionStatus.Error)
|
||||
{
|
||||
ChainStatus = ChainStatus.Error;
|
||||
OnError(Enumerator.Current.GetError());
|
||||
}
|
||||
if (status == ExecutionStatus.Continue)
|
||||
{
|
||||
// 中断(coroutine)
|
||||
ChainStatus = ChainStatus.Continue;
|
||||
return ExecutionStatus.Continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Enumerator.MoveNext())
|
||||
{
|
||||
// 終了
|
||||
ChainStatus = ChainStatus.Done;
|
||||
return ExecutionStatus.Done;
|
||||
}
|
||||
|
||||
if (Enumerator.Current.Schedulder != null)
|
||||
{
|
||||
// Scheduleして中断
|
||||
ChainStatus = ChainStatus.Continue;
|
||||
Enumerator.Current.Schedulder.Enqueue(this);
|
||||
return ExecutionStatus.Done;
|
||||
}
|
||||
|
||||
return Next();
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Scripts/DepthFirstScheduler/TaskChain.cs.meta
Normal file
12
Scripts/DepthFirstScheduler/TaskChain.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 38fc7e076ba93a847ad72d3d459d06b6
|
||||
timeCreated: 1520084019
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
41
Scripts/DepthFirstScheduler/Unit.cs
Normal file
41
Scripts/DepthFirstScheduler/Unit.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
|
||||
namespace DepthFirstScheduler
|
||||
{
|
||||
[Serializable]
|
||||
public struct Unit : IEquatable<Unit>
|
||||
{
|
||||
static readonly Unit @default = new Unit();
|
||||
|
||||
public static Unit Default { get { return @default; } }
|
||||
|
||||
public static bool operator ==(Unit first, Unit second)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool operator !=(Unit first, Unit second)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Equals(Unit other)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is Unit;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "()";
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Scripts/DepthFirstScheduler/Unit.cs.meta
Normal file
12
Scripts/DepthFirstScheduler/Unit.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 98bd42f8c3a895d4bac6cbcf523878bb
|
||||
timeCreated: 1520081817
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user