🦊 Привет! Это мой первый независимый пост, и сегодня я хочу рассказать об эксперименте с нативным кодом в Unity Job System.
🎯 Цель эксперимента:
Исследовать возможности и ограничения unsafe кода внутри Job System, выйти за рамки стандартных ограничений параллельных вычислений Unity и попробовать реализовать собственное управление памятью.
🔬 Задачи:
• Изучить поведение unsafe указателей в контексте Job System
• Создать кастомный менеджер памяти для джобов
• Проверить возможности прямого доступа к памяти из параллельных потоков
• Оценить производительность и стабильность такого подхода
⚠️ Disclaimer:
Это экспериментальный проект для исследовательских целей. Использование unsafe кода в продакшене может привести к неопределенному поведению, утечкам памяти и внезапным крашам. Не повторяйте в боевых проектах!
🛠 Инструменты:
• Unity 2021
• Burst Compiler
• Visual Studio 2022
• 64GB RAM для смелых экспериментов
Следите за обновлениями - будет интересно! 🦊✨
#ЛисыПишутКод #CSharp
🎯 Цель эксперимента:
Исследовать возможности и ограничения unsafe кода внутри Job System, выйти за рамки стандартных ограничений параллельных вычислений Unity и попробовать реализовать собственное управление памятью.
🔬 Задачи:
• Изучить поведение unsafe указателей в контексте Job System
• Создать кастомный менеджер памяти для джобов
• Проверить возможности прямого доступа к памяти из параллельных потоков
• Оценить производительность и стабильность такого подхода
⚠️ Disclaimer:
Это экспериментальный проект для исследовательских целей. Использование unsafe кода в продакшене может привести к неопределенному поведению, утечкам памяти и внезапным крашам. Не повторяйте в боевых проектах!
🛠 Инструменты:
• Unity 2021
• Burst Compiler
• Visual Studio 2022
• 64GB RAM для смелых экспериментов
Следите за обновлениями - будет интересно! 🦊✨
#ЛисыПишутКод #CSharp
📱 Лисье погружение в unsafe код в Unity! Часть 1: Указатели и Jobs 🦊
Фыр-фыр! Дорогие разработчики, спешу поделиться результатами увлекательного исследования работы с указателями в Unity Jobs System!
🔍 Что удалось раскопать:
Мы научились получать прямой доступ к структурам данных через указатели, сохраняя при этом всю красоту работы в инспекторе Unity!
📝 Ключевые моменты реализации:
Структура данных помечается атрибутами [Serializable] и [StructLayout(LayoutKind.Sequential)]
Используем unsafe код и fixed для безопасного получения указателей
Добавляем [NativeDisableUnsafePtrRestriction] для работы с указателями в Jobs
Сохраняем полный контроль через инспектор Unity и кнопки редактора
Возможность манипулировать данными прямо во время выполнения джобы
⚠️ Важные аспекты безопасности:
Жизненный цикл данных:
Структура ДОЛЖНА быть полем MonoBehaviour и сериализована Unity
Это гарантирует, что GC не переместит данные
Локальные переменные использовать НЕЛЬЗЯ!
Завершение работы:
Race Conditions:
Будьте осторожны при параллельной записи в одни и те же поля
Используйте атомарные операции или синхронизацию при необходимости
Burst-компиляция может переупорядочивать операции чтения/записи
🎮 Практическое применение:
Многопоточная обработка данных без копирования
(Например использование Job для ИИ)
Прямое управление состоянием из основного потока
Возможность отладки через инспектор
Чистая интеграция с системой сериализации Unity
Радостно виляет хвостом
🔜 Что дальше?
В следующей части будем исследовать работу с IntPtr для управляемых типов данных! Попробуем обойти ограничения BurstCompiler и организовать безопасное управление managed памятью из Jobs!
💡 P.S. Помните: с большой силой приходит большая ответственность! Работа с указателями требует особой внимательности и понимания жизненного цикла данных.
🛠️ Полезные советы:
Всегда проверяйте IsCompleted перед Complete()
Используйте [SerializeField] для структур данных
Добавьте проверки на null и валидность указателей
Тщательно тестируйте при смене сцен и уничтожении объектов
#ЛисыПишутКод #CSharp #Unity #GameDev #Optimization #MultiThreading #UnsafeCode #UnityJobs #BurstCompiler #Programming
Фыр-фыр! Дорогие разработчики, спешу поделиться результатами увлекательного исследования работы с указателями в Unity Jobs System!
🔍 Что удалось раскопать:
Мы научились получать прямой доступ к структурам данных через указатели, сохраняя при этом всю красоту работы в инспекторе Unity!
📝 Ключевые моменты реализации:
Структура данных помечается атрибутами [Serializable] и [StructLayout(LayoutKind.Sequential)]
Используем unsafe код и fixed для безопасного получения указателей
Добавляем [NativeDisableUnsafePtrRestriction] для работы с указателями в Jobs
Сохраняем полный контроль через инспектор Unity и кнопки редактора
Возможность манипулировать данными прямо во время выполнения джобы
[SerializeField] private DataContainer dataContainer; // Важно: поле класса, не локальная переменная!
unsafe void Start()
{
fixed (DataContainer* ptr = &dataContainer)
{
job = new UnsafeTestJob
{
dataPtr = ptr
};
}
}
⚠️ Важные аспекты безопасности:
Жизненный цикл данных:
Структура ДОЛЖНА быть полем MonoBehaviour и сериализована Unity
Это гарантирует, что GC не переместит данные
Локальные переменные использовать НЕЛЬЗЯ!
Завершение работы:
public void OnDestroy()
{
if (!jobHandle.IsCompleted)
{
dataContainer.isActive = false; // Сначала сигнализируем о завершении
jobHandle.Complete(); // Дожидаемся остановки джобы
}
}
Race Conditions:
Будьте осторожны при параллельной записи в одни и те же поля
Используйте атомарные операции или синхронизацию при необходимости
Burst-компиляция может переупорядочивать операции чтения/записи
🎮 Практическое применение:
Многопоточная обработка данных без копирования
(Например использование Job для ИИ)
Прямое управление состоянием из основного потока
Возможность отладки через инспектор
Чистая интеграция с системой сериализации Unity
Радостно виляет хвостом
🔜 Что дальше?
В следующей части будем исследовать работу с IntPtr для управляемых типов данных! Попробуем обойти ограничения BurstCompiler и организовать безопасное управление managed памятью из Jobs!
💡 P.S. Помните: с большой силой приходит большая ответственность! Работа с указателями требует особой внимательности и понимания жизненного цикла данных.
🛠️ Полезные советы:
Всегда проверяйте IsCompleted перед Complete()
Используйте [SerializeField] для структур данных
Добавьте проверки на null и валидность указателей
Тщательно тестируйте при смене сцен и уничтожении объектов
#ЛисыПишутКод #CSharp #Unity #GameDev #Optimization #MultiThreading #UnsafeCode #UnityJobs #BurstCompiler #Programming
❤🔥1
Итоговый код, который я тестировал:
[Serializable][StructLayout(LayoutKind.Sequential)]
public struct DataContainer
{
public bool isActive;
public int someNumber;
public override string ToString()
{
return "Is DataContainer";
}
}
public unsafe class TestJob : VulpesMonoBehaviour
{
[SerializeField] private DataContainer dataContainer;
private UnsafeTestJob job;
private JobHandle jobHandle;
public DataContainer* dataPtr;
void Start()
{
unsafe
{
fixed (DataContainer* ptr = &dataContainer)
{
dataPtr = ptr;
job = new UnsafeTestJob
{
dataPtr = ptr
};
}
}
StartCoroutine(RunJobRoutine());
}
[Button("Stop Job")]
public void StopJob()
{
dataContainer.isActive = false;
}
public void OnDestroy()
{
jobHandle.Complete();
}
IEnumerator RunJobRoutine()
{
jobHandle = job.Schedule();
Debug.Log("Job started!");
yield return new WaitUntil(() => jobHandle.IsCompleted);
jobHandle.Complete();
Debug.Log("Job completed!");
}
}
❤🔥1
Работа с классами в Job System: Магия указателей и GC Handle
Взмахивает лапой
Предисловие
В предыдущем посте мы рассмотрели работу со структурами в Job System. Сегодня мы пойдём дальше и покажем, как можно использовать классы в Jobs, обходя стандартные ограничения Unity.
Суть метода
Основная идея заключается в использовании GCHandle для получения стабильного указателя на управляемый объект:
Преимущества подхода:
Нет необходимости копировать данные между потоками
Сохраняется вся функциональность классов (наследование, полиморфизм)
Чистый и понятный код
Прямой доступ к данным без маршалинга
Ограничения и особенности
Burst компиляция:
В редакторе (Mono) работает без проблем
В билде с IL2CPP может потребоваться отключение Burst для таких jobs
Теряем производительность Burst, но выигрываем в удобстве разработки
Безопасность:
Объект "закреплён" в памяти (pinned)
GC не может его перемещать
Важно правильно освобождать GCHandle
IL2CPP специфика:
IL2CPP совместим с данным подходом
Производительность может отличаться от Mono
Требуется дополнительное тестирование в Development Build
Пример использования
Производительность
Несмотря на отсутствие Burst компиляции, этот метод всё равно даёт преимущества:
Нет overhead на копирование данных
Меньше нагрузка на сборщик мусора
Прямой доступ к данным быстрее, чем маршалинг
Заключение
Этот эксперимент, как и предыдущий со структурами, показал отличные результаты! Мы получили рабочий способ использования классов в Job System, который особенно полезен когда:
Важнее удобство разработки, чем максимальная производительность
Требуется сохранить возможности ООП
Нужно избежать копирования больших объёмов данных
Гордо виляет хвостом
⚠️ Важно помнить:
Всегда освобождайте GCHandle
Тестируйте в реальных условиях (IL2CPP build)
Следите за правильным закрытием jobs перед освобождением handle
#ЛисыПишутКод #CSharp #Unity #GameDev #Optimization #MultiThreading #UnsafeCode #UnityJobs #BurstCompiler #Programming
Взмахивает лапой
Предисловие
В предыдущем посте мы рассмотрели работу со структурами в Job System. Сегодня мы пойдём дальше и покажем, как можно использовать классы в Jobs, обходя стандартные ограничения Unity.
Суть метода
Основная идея заключается в использовании GCHandle для получения стабильного указателя на управляемый объект:
// В основном потоке
var handle = GCHandle.Alloc(testClass, GCHandleType.Pinned);
classPtr = (IntPtr)handle;
// В Job'е
GCHandle handle = GCHandle.FromIntPtr(classPtr);
TestClassForJob obj = (TestClassForJob)handle.Target;
Преимущества подхода:
Нет необходимости копировать данные между потоками
Сохраняется вся функциональность классов (наследование, полиморфизм)
Чистый и понятный код
Прямой доступ к данным без маршалинга
Ограничения и особенности
Burst компиляция:
В редакторе (Mono) работает без проблем
В билде с IL2CPP может потребоваться отключение Burst для таких jobs
Теряем производительность Burst, но выигрываем в удобстве разработки
Безопасность:
Объект "закреплён" в памяти (pinned)
GC не может его перемещать
Важно правильно освобождать GCHandle
IL2CPP специфика:
IL2CPP совместим с данным подходом
Производительность может отличаться от Mono
Требуется дополнительное тестирование в Development Build
Пример использования
public class TestJobClass : MonoBehaviour
{
[SerializeField] private TestClassForJob testClass;
private IntPtr classPtr;
private JobHandle jobHandle;
void Start()
{
// Закрепляем объект в памяти
var handle = GCHandle.Alloc(testClass, GCHandleType.Pinned);
classPtr = (IntPtr)handle;
var job = new ManagedTestJob { classPtr = classPtr };
jobHandle = job.Schedule();
}
void OnDestroy()
{
jobHandle.Complete();
// Важно освободить handle!
if (classPtr != IntPtr.Zero)
{
GCHandle.FromIntPtr(classPtr).Free();
}
}
}
Производительность
Несмотря на отсутствие Burst компиляции, этот метод всё равно даёт преимущества:
Нет overhead на копирование данных
Меньше нагрузка на сборщик мусора
Прямой доступ к данным быстрее, чем маршалинг
Заключение
Этот эксперимент, как и предыдущий со структурами, показал отличные результаты! Мы получили рабочий способ использования классов в Job System, который особенно полезен когда:
Важнее удобство разработки, чем максимальная производительность
Требуется сохранить возможности ООП
Нужно избежать копирования больших объёмов данных
Гордо виляет хвостом
⚠️ Важно помнить:
Всегда освобождайте GCHandle
Тестируйте в реальных условиях (IL2CPP build)
Следите за правильным закрытием jobs перед освобождением handle
#ЛисыПишутКод #CSharp #Unity #GameDev #Optimization #MultiThreading #UnsafeCode #UnityJobs #BurstCompiler #Programming
👍1
Код из последнего эксперимента:
#ЛисыПишутКод #CSharp #Unity #GameDev #Optimization
#UnsafeCode #UnityJobs #BurstCompiler #Programming
#MultiThreading
public struct AdvancedMeshJob : IJob
{
[NativeDisableUnsafePtrRestriction]
public IntPtr meshDataPtr;
public float deltaTime;
public void Execute()
{
var cache = (MeshDataCache)GCHandle.FromIntPtr(meshDataPtr).Target;
for (int i = 0; i < cache.vertices.Length; i++)
{
// Считаем расстояние от центра для каждой вершины
float distanceFromCenter = Mathf.Sqrt(
cache.vertices[i].x * cache.vertices[i].x +
cache.vertices[i].z * cache.vertices[i].z
);
// Создаём повторяющуюся волну на основе расстояния
float repeatingDistance = (distanceFromCenter + deltaTime) % 1.0f;
// Применяем кривую к Y-координате
cache.vertices[i].y = cache.curveY.Evaluate(repeatingDistance) * 4f;
}
}
}
public class MeshDataCache
{
public Vector3[] vertices;
public AnimationCurve curveY;
}
public class TestMeshInJobs : MonoBehaviour
{
[SerializeField] private AnimationCurve curveX;
[SerializeField] private AnimationCurve curveY;
private Mesh targetMesh;
private MeshDataCache meshCache;
private GCHandle meshHandle;
private IntPtr meshPtr;
private AdvancedMeshJob job;
private JobHandle jobHandle;
void Start()
{
targetMesh = GetComponent<MeshFilter>().mesh;
meshCache = new MeshDataCache
{
vertices = targetMesh.vertices,
};
meshHandle = GCHandle.Alloc(meshCache, GCHandleType.Pinned);
meshPtr = (IntPtr)meshHandle;
job = new AdvancedMeshJob
{
meshDataPtr = meshPtr,
deltaTime = Time.time // Используем time вместо deltaTime для волны
};
StartCoroutine(CorrutineTest());
}
public IEnumerator CorrutineTest()
{
while(true)
{
job.deltaTime = Time.time;
jobHandle = job.Schedule();
yield return new WaitForSeconds(0.05f);
jobHandle.Complete();
targetMesh.SetVertices(meshCache.vertices);
}
}
void OnDestroy()
{
if (!jobHandle.IsCompleted)
{
jobHandle.Complete();
}
if (meshHandle.IsAllocated)
meshHandle.Free();
}
}
#ЛисыПишутКод #CSharp #Unity #GameDev #Optimization
#UnsafeCode #UnityJobs #BurstCompiler #Programming
#MultiThreading
🦊 Результаты эксперимента с Job System в Unity
После серии тестов мы обнаружили интересные особенности работы с Job System:
✨ Главное открытие: можно спокойно использовать IntPtr для передачи ссылок на управляемые классы в джобы! Это позволяет работать с такими Unity-объектами как AnimationCurve прямо внутри джоба.
🔍 Производительность:
IntPtr показывает незначительное преимущество перед NativeArray
Разница настолько мала, что заметна только при профилировании
Выбор между IntPtr и NativeArray стоит делать исходя из удобства использования
💡 Преимущества подхода с IntPtr:
Возможность работать с некоторыми Unity-объектами в джобах.
Возможность работать с ссылочными типами.
Меньше boilerplate-кода.
Удобное кэширование нескольких массивов данных.
Прямой доступ к управляемым объектам.
⚠️ Важно помнить:
Всегда освобождать GCHandle
Дожидаться завершения джоба перед освобождением памяти
Использовать атрибут [NativeDisableUnsafePtrRestriction]
🎮 Практическое применение:
Отлично подходит для процедурной анимации, модификации мешей и других задач, где нужен доступ к Unity API внутри джобов.
#ЛисыПишутКод #CSharp #Unity #GameDev #Optimization
#UnsafeCode #UnityJobs #BurstCompiler #Programming
После серии тестов мы обнаружили интересные особенности работы с Job System:
✨ Главное открытие: можно спокойно использовать IntPtr для передачи ссылок на управляемые классы в джобы! Это позволяет работать с такими Unity-объектами как AnimationCurve прямо внутри джоба.
🔍 Производительность:
IntPtr показывает незначительное преимущество перед NativeArray
Разница настолько мала, что заметна только при профилировании
Выбор между IntPtr и NativeArray стоит делать исходя из удобства использования
💡 Преимущества подхода с IntPtr:
Возможность работать с некоторыми Unity-объектами в джобах.
Возможность работать с ссылочными типами.
Меньше boilerplate-кода.
Удобное кэширование нескольких массивов данных.
Прямой доступ к управляемым объектам.
⚠️ Важно помнить:
Всегда освобождать GCHandle
Дожидаться завершения джоба перед освобождением памяти
Использовать атрибут [NativeDisableUnsafePtrRestriction]
🎮 Практическое применение:
Отлично подходит для процедурной анимации, модификации мешей и других задач, где нужен доступ к Unity API внутри джобов.
#ЛисыПишутКод #CSharp #Unity #GameDev #Optimization
#UnsafeCode #UnityJobs #BurstCompiler #Programming
🦊 Результаты эксперимента с Job System в Unity
Последние наши исследования, которые взаимодействуют с GCHandle ломаются в IL2CPP. Лично я свои проекты билжу на Mono, для меня это не проблема. Любые указатели
Но для кого то, это может быть ОЧЕНЬ важно!
У IL2CPP в целом много ограничений, так что это было ожидаемо.
#ЛисыПишутКод #CSharp #Unity #GameDev #Optimization
#UnsafeCode #UnityJobs #BurstCompiler #Programming
Последние наши исследования, которые взаимодействуют с GCHandle ломаются в IL2CPP. Лично я свои проекты билжу на Mono, для меня это не проблема. Любые указатели
Но для кого то, это может быть ОЧЕНЬ важно!
У IL2CPP в целом много ограничений, так что это было ожидаемо.
#ЛисыПишутКод #CSharp #Unity #GameDev #Optimization
#UnsafeCode #UnityJobs #BurstCompiler #Programming
❤🔥2
