From d7d1ad4bf95a7184ca4c0855808acc73b7512d63 Mon Sep 17 00:00:00 2001 From: TORISOUP Date: Thu, 19 Apr 2018 01:14:27 +0900 Subject: [PATCH 1/2] Add ThreadPoolScheduler --- Scripts/UniTask/ThreadPoolScheduler.cs | 42 ++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 Scripts/UniTask/ThreadPoolScheduler.cs diff --git a/Scripts/UniTask/ThreadPoolScheduler.cs b/Scripts/UniTask/ThreadPoolScheduler.cs new file mode 100644 index 000000000..94e6316e7 --- /dev/null +++ b/Scripts/UniTask/ThreadPoolScheduler.cs @@ -0,0 +1,42 @@ +using System; + +namespace UniTask +{ + 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() + { + } + } + } +} From bc31e2d60049673783fbaff5923b4a94d4bae276 Mon Sep 17 00:00:00 2001 From: TORISOUP Date: Thu, 19 Apr 2018 01:14:40 +0900 Subject: [PATCH 2/2] Use Scheduler.ThreadPool --- Scripts/Format/VRMImporter.cs | 30 +++--- Scripts/UniTask/MainThreadDispatcher.cs | 39 +------ Scripts/UniTask/Scheduler.cs | 6 +- Scripts/UniTask/StepScheduler.cs | 56 +++++++--- Scripts/UniTask/TaskChain.cs | 2 +- Scripts/UniTask/ThreadScheduler.cs | 134 +++++++++++++----------- 6 files changed, 135 insertions(+), 132 deletions(-) diff --git a/Scripts/Format/VRMImporter.cs b/Scripts/Format/VRMImporter.cs index be9a70ae9..38894249b 100644 --- a/Scripts/Format/VRMImporter.cs +++ b/Scripts/Format/VRMImporter.cs @@ -564,7 +564,7 @@ namespace VRM var schedulable = Schedulable.Create(); schedulable - .AddTask(MainThreadDispatcher.Instance.ThreadScheduler, () => + .AddTask(Scheduler.ThreadPool, () => { ctx.GLTF.baseDir = Path.GetDirectoryName(ctx.Path); foreach (var buffer in ctx.GLTF.buffers) @@ -573,44 +573,44 @@ namespace VRM } return Unit.Default; }) - .ContinueWith(MainThreadDispatcher.Instance.ThreadScheduler, _ => + .ContinueWith(Scheduler.ThreadPool, _ => { return glTF_VRM_Material.Parse(ctx.Json); }) - .ContinueWith(MainThreadDispatcher.Instance.UnityScheduler, x => + .ContinueWith(Scheduler.MainThread, x => { // material function ctx.CreateMaterial = VRMImporter.GetMaterialFunc(x); }) - .OnExecute(MainThreadDispatcher.Instance.UnityScheduler, parent => + .OnExecute(Scheduler.ThreadPool, parent => { // textures for (int i = 0; i < ctx.GLTF.textures.Count; ++i) { var index = i; - parent.AddTask(MainThreadDispatcher.Instance.UnityScheduler, + parent.AddTask(Scheduler.MainThread, () => gltfImporter.ImportTexture(ctx.GLTF, index)) - .ContinueWith(MainThreadDispatcher.Instance.ThreadScheduler, x => ctx.Textures.Add(x)); + .ContinueWith(Scheduler.ThreadPool, x => ctx.Textures.Add(x)); } }) - .ContinueWithCoroutine(MainThreadDispatcher.Instance.UnityScheduler, () => LoadMaterials(ctx)) - .OnExecute(MainThreadDispatcher.Instance.UnityScheduler, parent => + .ContinueWithCoroutine(Scheduler.MainThread, () => LoadMaterials(ctx)) + .OnExecute(Scheduler.ThreadPool, parent => { // meshes for (int i = 0; i < ctx.GLTF.meshes.Count; ++i) { var index = i; - parent.AddTask(MainThreadDispatcher.Instance.ThreadScheduler, + parent.AddTask(Scheduler.ThreadPool, () => gltfImporter.ReadMesh(ctx, index)) - .ContinueWith(MainThreadDispatcher.Instance.UnityScheduler, x => gltfImporter.BuildMesh(ctx, x)) - .ContinueWith(MainThreadDispatcher.Instance.ThreadScheduler, x => ctx.Meshes.Add(x)) + .ContinueWith(Scheduler.MainThread, x => gltfImporter.BuildMesh(ctx, x)) + .ContinueWith(Scheduler.ThreadPool, x => ctx.Meshes.Add(x)) ; } }) - .ContinueWithCoroutine(MainThreadDispatcher.Instance.UnityScheduler, () => LoadNodes(ctx)) - .ContinueWithCoroutine(MainThreadDispatcher.Instance.UnityScheduler, () => BuildHierarchy(ctx)) - .ContinueWith(MainThreadDispatcher.Instance.UnityScheduler, _ => VRMImporter.OnLoadModel(ctx)) - .Subscribe(MainThreadDispatcher.Instance.UnityScheduler, + .ContinueWithCoroutine(Scheduler.MainThread, () => LoadNodes(ctx)) + .ContinueWithCoroutine(Scheduler.MainThread, () => BuildHierarchy(ctx)) + .ContinueWith(Scheduler.MainThread, _ => VRMImporter.OnLoadModel(ctx)) + .Subscribe(Scheduler.MainThread, _ => { /* diff --git a/Scripts/UniTask/MainThreadDispatcher.cs b/Scripts/UniTask/MainThreadDispatcher.cs index 95fd5b0c6..d0bd8c208 100644 --- a/Scripts/UniTask/MainThreadDispatcher.cs +++ b/Scripts/UniTask/MainThreadDispatcher.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using UnityEngine; - namespace UniTask { /// @@ -11,37 +10,6 @@ namespace UniTask /// public class MainThreadDispatcher : MonoBehaviour { - StepScheduler m_unityScheduler; - /// - /// Dequeueとタスク実行がUnityのMainThread上であるこを保証する - /// - public StepScheduler UnityScheduler - { - get - { - if (m_unityScheduler == null) - { - m_unityScheduler = new StepScheduler(); - } - return m_unityScheduler; - } - } - - ThreadScheduler m_threadScheduler; - /// - /// Dequeuとタスク実行がWorkerThread上で実行される - /// - public ThreadScheduler ThreadScheduler - { - get - { - if (m_threadScheduler == null) - { - m_threadScheduler = new ThreadScheduler(); - } - return m_threadScheduler; - } - } [Header("Debug")] public int TaskCount; @@ -61,7 +29,7 @@ namespace UniTask private void Update() { - TaskCount = UnityScheduler.UpdateAndGetTaskCount(); + TaskCount = Scheduler.MainThread.UpdateAndGetTaskCount(); } static MainThreadDispatcher instance; @@ -166,10 +134,9 @@ namespace UniTask initialized = instance != null; } - if (m_threadScheduler != null) + if (Scheduler.SingleWorkerThread != null) { - m_threadScheduler.Dispose(); - m_threadScheduler = null; + Scheduler.SingleWorkerThread.Dispose(); } } diff --git a/Scripts/UniTask/Scheduler.cs b/Scripts/UniTask/Scheduler.cs index 12fb7bb3a..90abc3e1a 100644 --- a/Scripts/UniTask/Scheduler.cs +++ b/Scripts/UniTask/Scheduler.cs @@ -1,6 +1,8 @@ -namespace UniTask +using System; + +namespace UniTask { - public interface IScheduler + public interface IScheduler : IDisposable { void Enqueue(TaskChain item); } diff --git a/Scripts/UniTask/StepScheduler.cs b/Scripts/UniTask/StepScheduler.cs index 7af5d3d98..a394763e9 100644 --- a/Scripts/UniTask/StepScheduler.cs +++ b/Scripts/UniTask/StepScheduler.cs @@ -1,30 +1,52 @@ namespace UniTask { - public class StepScheduler : IScheduler + public static partial class Scheduler { - LockQueue m_taskQueue = new LockQueue(); - public void Enqueue(TaskChain item) + private static StepScheduler mainThread; + + public static StepScheduler MainThread { - m_taskQueue.Enqueue(item); + get + { + if (mainThread != null) return mainThread; + mainThread = new StepScheduler(); + MainThreadDispatcher.Initialize(); + return mainThread; + } } - TaskChain m_chain; - public int UpdateAndGetTaskCount() + public class StepScheduler : IScheduler { - if (m_chain != null) + LockQueue m_taskQueue = new LockQueue(); + + public void Enqueue(TaskChain item) { - var status=m_chain.Next(); - if(status==ExecutionStatus.Continue) - { - // m_item継続中 - return m_taskQueue.Count; - } - m_chain = null; + m_taskQueue.Enqueue(item); } - int count; - m_chain = m_taskQueue.Dequeue(out count); - return count; + 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() + { + } } } } diff --git a/Scripts/UniTask/TaskChain.cs b/Scripts/UniTask/TaskChain.cs index b15688b50..89b93cfe0 100644 --- a/Scripts/UniTask/TaskChain.cs +++ b/Scripts/UniTask/TaskChain.cs @@ -32,7 +32,7 @@ namespace UniTask if (item.Enumerator.Current.Schedulder == null) { // default - MainThreadDispatcher.Instance.UnityScheduler.Enqueue(item); + Scheduler.MainThread.Enqueue(item); } else { diff --git a/Scripts/UniTask/ThreadScheduler.cs b/Scripts/UniTask/ThreadScheduler.cs index 24b462438..e5a797588 100644 --- a/Scripts/UniTask/ThreadScheduler.cs +++ b/Scripts/UniTask/ThreadScheduler.cs @@ -3,87 +3,99 @@ using System.Threading; namespace UniTask { - public class ThreadScheduler : IScheduler, IDisposable + public static partial class Scheduler { - MonitorQueue m_queue = new MonitorQueue(); + private static IScheduler singleWorkerTrehad; - Thread m_thread; - - public ThreadScheduler() + public static IScheduler SingleWorkerThread { - // start worker thread - m_thread = new Thread(new ParameterizedThreadStart(Worker)); - m_thread.Start(m_queue); + get { return singleWorkerTrehad ?? (singleWorkerTrehad = new ThreadScheduler()); } } - static void Worker(Object arg) + public class ThreadScheduler : IScheduler { - MonitorQueue queue = (MonitorQueue)arg; - while (true) - { - var chain = queue.Dequeue(); - if (chain == null) - { - break; - } + MonitorQueue m_queue = new MonitorQueue(); + 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 queue = (MonitorQueue)arg; while (true) { - var status = chain.Next(); - if (status != ExecutionStatus.Continue) + var chain = queue.Dequeue(); + if (chain == null) { 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) + while (true) { - m_queue.Enqueue(null); - m_thread.Join(); - m_thread = null; + var status = chain.Next(); + if (status != ExecutionStatus.Continue) + { + break; + } } } - // TODO: アンマネージ リソース (アンマネージ オブジェクト) を解放し、下のファイナライザーをオーバーライドします。 - // TODO: 大きなフィールドを null に設定します。 - - disposedValue = true; + // end } - } - // TODO: 上の Dispose(bool disposing) にアンマネージ リソースを解放するコードが含まれる場合にのみ、ファイナライザーをオーバーライドします。 - // ~ThreadScheduler() { - // // このコードを変更しないでください。クリーンアップ コードを上の Dispose(bool disposing) に記述します。 - // Dispose(false); - // } + public void Enqueue(TaskChain item) + { + m_queue.Enqueue(item); + } - // このコードは、破棄可能なパターンを正しく実装できるように追加されました。 - public void Dispose() - { - // このコードを変更しないでください。クリーンアップ コードを上の Dispose(bool disposing) に記述します。 - Dispose(true); - // TODO: 上のファイナライザーがオーバーライドされる場合は、次の行のコメントを解除してください。 - // GC.SuppressFinalize(this); + #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 } - #endregion } }