Дабы не быть голословным, я решил в поддержку моего предыдущего поста провести некоторые тесты и рассказать: "Почему я не использую SendMessage() в Unity. Нет, в нем нет ничего плохого, я не хочу никого учить, просто выскажу свое мнение на этот счет.
Поехали!
Ранее я заявлял, что не стоит в своих скриптах использовать SendMessage() и предложил свой вариант обращения к методам объектов игровой сцены, аргументируя это тем, что SendMessage() очень уж медленный и небезопасный. Так а теперь обо всем по-порядку.
SendMessage() - ОЧЕНЬ! медленный.
Звучит не убедительно, не так ли? Ну чтож давайте проверим =)
Напишем небольшой тестик на основе скриптов из моего предыдущего поста.
780 000 - 820 000 вызовов за 1 секунду в редакторе. Неплохо в общем-то!
Закомментируем наш #define SEND_METOD и проверим результаты для GetComponent < T > ().
2 820 000 - 2 880 000 вызовов за 1 секунду! Хех, разница чувствуется.
А теперь, еще маленький эксперимент: создаем 5 клаасов c разными именами и кинем их на наш кубик. А теперь проверим еще раз:
660 000 - 680 000 вызовов для SendMessage().
Для GetComponent < T >() количество вызовов остается прежним, ну это итак понятно.
А теперь создадим еще один скриптик:
Поехали!
Ранее я заявлял, что не стоит в своих скриптах использовать SendMessage() и предложил свой вариант обращения к методам объектов игровой сцены, аргументируя это тем, что SendMessage() очень уж медленный и небезопасный. Так а теперь обо всем по-порядку.
SendMessage() - ОЧЕНЬ! медленный.
Звучит не убедительно, не так ли? Ну чтож давайте проверим =)
Напишем небольшой тестик на основе скриптов из моего предыдущего поста.
/*
IClickable.cs
*/
public interface IClickable
{
/*
Этот метод будет нашим подопытным, его
мы и будем вызывать миллионы-миллионы раз!
*/
void Active();
/*
А этот будет выводить на печать количество
вызванных функций.
*/
void Print();
}
Попробую писать компактней и убирать все лишнее. /*
ClickableObjects.cs
*/
using UnityEngine;
public class ClickableObjects : MonoBehaviour, IClickable
{
public virtual void Active(){}
public virtual void Print(){}
}
Интерфейсы и классы предназначенные в прошлом посте для большей наглядности мы опустим. Теперь никакого IDragable и DragWindow.
/*
SimpleButton.cs
*/
using UnityEngine;
public class SimpleButton : ClickableObjects
{
private int iterations = 0;
public override void Active()
{
this.iterations++;
}
public override void Print()
{
Debug.Log(iterations.ToString());
iterations = 0;
}
}
И, наконец, скрипт нашей камеры в котором и будет реализован алгоритм проверки.
/*
GuiCamera.cs
*/
// заккоментировать Define в случае тестирования GetComponent()
#define SEND_METOD
using UnityEngine;
[ExecuteInEditMode]
[RequireComponent (typeof(Camera))]
public class GuiCamera : MonoBehaviour
{
private Ray ray;
private RaycastHit hit;
private IClickable obj;
private GameObject obj_send;
private float dt = 0;
private void Awake()
{
Application.targetFrameRate = 2000;
QualitySettings.vSyncCount = 0;
}
private void Update()
{
dt+=Time.deltaTime;
ray = this.camera.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit, 200f))
{
Metod ();
}
}
private void Metod()
{
for(int i = 0; i < 20000; i++)
{
#if SEND_METOD
SendMetod();
#else
GetMetod();
#endif
}
}
/*
для SendMessage() пришлось подопытным
объектам присвоить тег "Clickable",
ато возникнут эксепшины, которые совсем
нам не нужны.
*/
private void SendMetod()
{
if(hit.transform.gameObject.tag == "Clickable")
{
obj_send = hit.transform.gameObject;
if(obj_send != null)
{
obj_send.SendMessage("Active");
if(dt>=1)
{
obj_send.SendMessage("Print");
dt = 0;
}
}
}
}
/*
метод описанный в моей педыдущей заметке
*/
private void GetMetod()
{
obj = (IClickable)hit.transform.GetComponent(typeof(IClickable));
if(obj != null)
{
obj.Active();
if(dt>=1)
{
obj.Print();
dt = 0;
}
}
}
}
Теперь собираем тестовый "агрегат". Создаем новый Unity проект. Удаляем камеру, кидаем на сцену EmptyObject и называем его TestCamera, к примеру. Меняем настройки камеры на необходимые нам. Добавляем на сцену 2 кубика и кидаем на них BoxCollider'ы. На один из кубиков кинем наш скрипт SimpleButton.cs и не забываем добавить тег "Clickable" и присвоить его этому кубику. Вроде бы всё! Теперь можно запускать тесты.Сначала для SendMessage():780 000 - 820 000 вызовов за 1 секунду в редакторе. Неплохо в общем-то!
Закомментируем наш #define SEND_METOD и проверим результаты для GetComponent < T > ().
2 820 000 - 2 880 000 вызовов за 1 секунду! Хех, разница чувствуется.
А теперь, еще маленький эксперимент: создаем 5 клаасов c разными именами и кинем их на наш кубик. А теперь проверим еще раз:
660 000 - 680 000 вызовов для SendMessage().
Для GetComponent < T >() количество вызовов остается прежним, ну это итак понятно.
А теперь создадим еще один скриптик:
/*
TestScript.cs
*/
using UnityEngine;
public class TestScript : MonoBehaviour
{
void Active(int a) {}
}
Если его кинуть на наш кубик, то редактор зависнет =) Так что лучше этот эксперимент не повторять. Думаю коментарии излишни! Вот, наверное, поэтому я и не использую SendMessage(). Пересчитывать скорость вызова в миллисекунды не буду, думаю итак понятно как это сделать. И вообще мои тесты могут показаться спецефическими, не говоря уже о том, что я не приводил показатели на мобильных устройствах. Хотя там картина еще более очевидна. Всем спасибо за внимание!
Комментариев нет:
Отправить комментарий