Skip to content

Instantly share code, notes, and snippets.

@divide-by-zero
Last active September 20, 2015 17:34
Show Gist options
  • Save divide-by-zero/5b2e7f333978c0f501cd to your computer and use it in GitHub Desktop.
Save divide-by-zero/5b2e7f333978c0f501cd to your computer and use it in GitHub Desktop.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace GameUtil
{
public class TaskScheduler : MonoBehaviour
{
private static TaskScheduler instance;
private readonly Dictionary<Guid, IEnumerator> iteratorList = new Dictionary<Guid, IEnumerator>();
public float targetTime = 0.01f;
public static TaskScheduler Instance
{
get
{
if (instance != null) return instance;
instance = FindObjectOfType(typeof(TaskScheduler)) as TaskScheduler; //既にシーンに存在する場合はそれを使用
if (!instance)
{
instance = new GameObject("TaskScheduler").AddComponent<TaskScheduler>(); //さらにない場合は作成
}
return instance;
}
}
public Guid AddIterator(IEnumerator iterator)
{
var guid = Guid.NewGuid();
iteratorList.Add(guid, iterator);
return guid;
}
public void RemoveIterator(Guid guid)
{
if (iteratorList.ContainsKey(guid))
{
iteratorList.Remove(guid);
}
}
public void StopAllIterator()
{
iteratorList.Clear();
}
public Guid AddAction(Action act)
{
return AddIterator(ActionIterator(act));
}
public IEnumerator ActionIterator(Action act)
{
if(act != null)act();
yield return null;
}
public void Start()
{
StartCoroutine(Iterator());
}
private IEnumerator Iterator()
{
while (true)
{
var ts = Time.realtimeSinceStartup;
do
{
if (iteratorList.Count <= 0) break;
foreach (var itr in iteratorList.ToList())
{
if (itr.Value.MoveNext() == false)
{
iteratorList.Remove(itr.Key);
}
if (Time.realtimeSinceStartup - ts > targetTime) yield return null;
}
} while (Time.realtimeSinceStartup - ts <= targetTime);
yield return null;
}
}
}
}
using System.Collections;
using GameUtil;
using UnityEngine;
public class TaskSchedulerTest : MonoBehaviour
{
private void Update()
{
if (Input.GetMouseButtonDown(0))
{
//Bad case1
for (var i = 0; i < 100; ++i)
{
StartCoroutine(TestIterator(i));
}
//Bad case2
for (var i = 0; i < 1000; ++i)
{
Debug.Log("Hello" + i);
}
}
if (Input.GetMouseButtonDown(1))
{
//Good case1
for (var i = 0; i < 100; ++i)
{
TaskScheduler.Instance.AddIterator(TestIterator(i));
}
//Good case2
for (var i = 0; i < 1000; ++i)
{
var i1 = i;
TaskScheduler.Instance.AddAction(() => Debug.Log("Hello" + i1));
}
}
}
private IEnumerator TestIterator(int num)
{
for (var i = 0; i < 10; ++i)
{
Debug.Log("num:" + num + "(" + i + ")");
yield return null;
}
}
}
@divide-by-zero
Copy link
Author

これ何?

  • 重めの処理をStartCoroutineでyield return しながら回すのは良いとして、それを複数走らせる必要がある場合にFPSが落ちてしまうのが嫌で、1本のCoroutineに時間管理をさせつつ渡したIEnumratorを順次処理していく仕組みがあると便利かと思って作成。
  • ついでにActionも渡せられるようにした。 遅延実行されるのでキャプチャする変数に注意。
  • public float targetTime を超えるようなら1回処理が戻るので、60FPS維持なら0.016秒。 だけど、他にも処理が走っていると思うので、0.01fぐらいかなーと。 publicなので、AddIteratorする前にセットするか、先にシーンにTaskSchedulerをアタッチしたGameObjectを置いてInspectorで調整を。
  • 管理にGuid使っちゃったけどどうなのかな。これ。 

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment