잡 시스템은 버스트 컴파일러와 함께 사용할 때 가장 잘 작동합니다.버스트는 관리되는 오브젝트를 지원하지 않으므로, 잡의 데이터에 액세스하려면 관리되지 않는 타입을 사용해야 합니다.이것을 blittable 타입과 함께 사용하거나, 네이티브 메모리용 스레드 세이프 C# 래퍼인 Unity의 빌트인 NativeContainer
오브젝트를 사용합니다.또한 NativeContainer
오브젝트를 사용하면 잡이 사본으로 작업하는 대신 메인 스레드와 공유되는 데이터에 액세스할 수 있습니다.
Unity.Collections
네임스페이스에는 다음과 같은 빌트인 NativeContainer
오브젝트가 포함되어 있습니다.
NativeArray
:관리되는 코드에 네이티브 메모리 버퍼를 노출하는 관리되지 않는 배열NativeSlice
:특정 위치에서 특정 길이까지 NativeArray
의 하위 세트를 가져옵니다.참고:컬렉션 패키지에는 추가 NativeContainer
의 항목이 들어 있습니다. 추가 타입에 대한 전체 리스트는 컬렉션 타입에 대한 컬렉션 문서를 참조하십시오.
기본적으로 잡이 NativeContainer
인스턴스에 액세스할 수 있는 경우 읽기 및 쓰기 액세스 권한이 모두 있습니다.이 설정은 성능 저하를 초래할 수 있습니다.이는 잡 시스템에서 NativeContainer
인스턴스에 대한 쓰기 권한이 있는 잡을 다른 잡과 동시에 예약하는 것을 허용하지 않기 때문입니다.
하지만 잡이 NativeContainer
인스턴스에 작성하지 않아도 된다면 [ReadOnly]
속성을 사용하여 다음과 같이 NativeContainer
를 표시할 수 있습니다.
[ReadOnly]
public NativeArray<int> input;
위 예에서는 첫 번째 NativeArray
에 대한 읽기 전용 액세스 권한이 있는 다른 잡과 동시에 잡을 실행할 수 있습니다.
NativeContainer
인스턴스를 생성할 때 필요한 메모리 할당 타입을 지정해야 합니다.사용하는 할당 타입은 네이티브 컨테이너를 얼마나 오랫동안 사용 가능하게 할 것인지에 따라 다릅니다.이렇게 하면 각 상황에서 가능한 최상의 성능을 얻을 수 있도록 할당량을 조정할 수 있습니다.
NativeContainer
메모리 할당 및 해제에는 세 가지 할당자 타입이 있습니다.NativeContainer
인스턴스를 인스턴스화할 때 다음과 같이 적절한 인스턴스를 지정해야 합니다.
Allocator.Temp
:가장 빠른 할당입니다.수명이 한 프레임 이하인 할당에 사용합니다.Temp
를 사용하여 잡의 멤버 필드에 저장된 NativeContainer
인스턴스에 할당을 전달할 수 없습니다.Allocator.TempJob
:Temp
보다는 느리지만 Persistent
보다는 빠른 할당입니다.4프레임의 수명 내에서 스레드 세이프 할당을 위해 사용합니다.중요:이 할당 타입을 4프레임 이내에 ’처분’해야 하며, 그렇지 않으면 콘솔에 네이티브 코드에서 생성된 경고가 출력됩니다.대부분의 작은 잡은 이 할당 타입을 사용합니다.Allocator.Persistent
:가장 느린 할당이지만 필요한 경우 애플리케이션의 수명 기간 동안 필요한 만큼 오래 사용할 수 있습니다.이것은 malloc
로 직접 호출하기 위한 래퍼입니다.더 긴 잡은 이 NativeContainer 할당 타입을 사용할 수 있습니다.성능이 필수적인 경우 Persistent
를 사용하지 마십시오.예제:
NativeArray<float> result = new NativeArray<float>(1, Allocator.TempJob);
참고:위 예시에서 숫자 1은 NativeArray의 크기를 나타냅니다.이 경우 결과에 하나의 데이터만 저장하기 때문에 배열 요소가 하나만 있습니다.
안전 시스템은 모든 NativeContainer
인스턴스에 내장되어 있습니다.이것은 NativeContainer
인스턴스에 읽거나 쓰는 내용을 추적하고, 해당 정보를 사용하여 여러 잡과 스레드에서 결정론적인 방식으로 작동하도록 NativeContainer
사용에 대한 특정 규칙을 적용합니다.
예를 들어, 두 개의 독립적인 예약된 잡이 동일한 NativeArray
에 쓰는 경우, 어떤 잡이 먼저 실행될지 예측할 수 없기 때문에 안전하지 않습니다.즉, 어떤 잡이 다른 잡의 데이터를 덮어쓰는지 알 수 없습니다.두 번째 잡을 예약하면 안전 시스템에서 명확한 오류 메시지와 함께 예외가 발생하며, 그 이유와 문제 해결 방법을 설명합니다.
동일한 NativeContainer
인스턴스에 쓰는 두 개의 잡을 예약하려면 종속성이 있는 작업을 예약할 수 있습니다.첫 번째 잡은 NativeContainer
에 쓰고, 실행이 완료되면 다음 잡은 동일한 NativeContainer
를 안전하게 읽고 씁니다.종속성을 도입하면 잡이 항상 일관된 순서로 실행되고 NativeContainer
의 결과 데이터가 결정론적이라는 것을 보장합니다.
안전 시스템을 통해 여러 잡이 동일한 데이터에서 동시에 읽을 수 있습니다.
이러한 읽기 및 쓰기 제한은 메인 스레드에서 데이터에 액세스할 때도 적용됩니다.예를 들어, 쓰기 잡이 완료되기 전에 NativeContainer의 콘텐츠를 읽으려고 하면 안전 시스템에서 오류가 발생합니다.마찬가지로, 읽기 또는 쓰기 잡이 아직 보류 중인 상태에서 NativeContainer에 쓰기를 시도하면 안전 시스템에서도 오류가 발생합니다.
또한, 네이티브 컨테이너는 ref return
을 구현하지 않기 때문에 NativeContainer
의 콘텐츠를 직접 변경할 수 없습니다.예를 들어 nativeArray[0]++;
는 nativeArray
에서 값을 업데이트하지 않는 var temp = nativeArray[0]; temp++;
쓰기와 동일합니다.
대신에 인덱스의 데이터를 로컬 임시 복사본으로 복사하고 해당 복사본을 수정한 후 다음과 같이 다시 저장해야 합니다.예시:
MyStruct temp = myNativeArray[i];
temp.memberVariable = 0;
myNativeArray[i] = temp;