Unityにおけるマルチスレッドの設計と実現
前言
プロジェクトの後期のため、久しぶりにもっと博しました.最近プロジェクトがオンラインになったので,急に暇になった.書きたいことが多い.まずマルチスレッドから始めましょう.個人のスレッドに対する理解はまだ十分ではありません.もっと良い見方があれば、コメントエリアで提出してほしいです.ありがとうございます.
マルチスレッド
1つのプログラムでは、独立して実行されるプログラムの一部を「スレッド」(Thread)と呼び、それを利用してプログラミングされる概念を「マルチスレッド処理」(Multithreading)と呼ぶ.
Unityでマルチスレッドを使うと何ができますか?
栗を挙げる時間です
/*---------------------------------------------------------------- // Copyright © 2016 Jhon // // FileName: Loom.cs // Describle: // Created By: Jhon // Date&Time: 2016 10 14 17:31:26 // Modify History: // //--------------------------------------------------------------*/
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
using System.Threading;
public class Loom : MonoBehaviour
{
}
#region StructMember
public struct DelayedQueueItem
{
public float time;
public Action action;
}
#endregion
#region Member
public static int mMaxThreads = 8;
private static Loom _current;
public static Loom Current
{
get
{
Initialize();
return _current;
}
}
private static int mNumThreads;
private static bool initialized;
private int _count;
private List _actions = new List();
private List _currentActions = new List();
private List _delayed = new List();
private List _currentDelayed = new List();
#endregion
#region MonoLife
void Awake()
{
_current = this;
initialized = true;
}
void OnEnable()
{
if (null == _current)
{
_current = this;
}
}
void OnDisable()
{
if (this == _current)
{
_current = null;
}
}
void Update()
{
lock (_actions)
{
_currentActions.Clear();
_currentActions.AddRange(_actions);
_actions.Clear();
}
for (int i = 0;i < _currentActions.Count;i++)
{
_currentActions[i]();
}
lock (_delayed)
{
_currentDelayed.Clear();
for(int i = _delayed.Count - 1;i > 0;i--)
{
if(_delayed[i].time > Time.time)
{
continue;
}
_currentDelayed.Add(_delayed[i]);
_delayed.RemoveAt(i);
}
}
for(int i = 0;i < _currentDelayed.Count;i++)
{
_currentDelayed[i].action();
}
}
#endregion
#region BusinessLogic
private static void Initialize()
{
if (initialized == true)return;
if (Application.isPlaying == false)return;
initialized = true;
var g = new GameObject("Loom");
_current = g.AddComponent();
}
private static void RunAction(object action)
{
try
{
((Action)action)();
}
catch(Exception e)
{
Log.Error(e.Message);
}
finally
{
Interlocked.Decrement(ref mNumThreads);
}
}
#endregion
#region PublicTools
public static void QueueOnMainThread(Action action, float time = 0.0f)
{
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 varAction)
{
Initialize();
while (mNumThreads >= mMaxThreads)
{
Thread.Sleep(1);
}
Interlocked.Increment(ref mNumThreads);
ThreadPool.QueueUserWorkItem(RunAction, varAction);
return null;
}
#endregion
最後に書く
Update関数ではforeachを使って遍歴できますが、私の別のブログではforeachを使うと16 BのGCがあると言いました.Updateでの操作であることを考慮して、forを使用して遍歴することを推奨します.以下にforeachバージョンを貼ります.
private void OldVersionUpdate()
{
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();
}
}