스레드를 대신하는 단일작업을 수행하는 가장 작은 단위인 'Job'을 만들어 멀티 스레드를 관리한다.
Job System을 사용하려면 using Unity.Jobs을 선언하여 한다.
멀티 스레드와는 다르게 메인 스레드에서 접근할 수 없는 메모리에 만들어진다.
메인 스레드에서 Job의 데이터에 접근하기 위해서 Native Container라는 '특수한 공유 메모리 타입'을 사용해야만 한다.
* Native Arra를 제외한 타입들은 ECS에서 제공하는 타입들로 PackageManager를 통해 Collections를 Import해야지만 사용 가능하다.
Native들을 선언할 때 기본적으로는 읽기 / 쓰기가 모두 가능하지만 별도로 권한을 부여할 수 있다. 또한 사용 용도에 따라 속성을 지정해주면 성능을 더 높일 수 있다.
[ReadOnly] public NativeArrat<int> result;
- 메모리에서 읽기만 가능하며, 다른 Job에서도 해당 Native Container에 접근할 수 있다.
[WriteOnly] public NativeArrat<int> result;
- 메모리에 쓰기만 가능하다. Job에서 해당 Native Container에 쓰기 작업을 하고 있다면 다른 Job에게 쓰기 권한을 주지 않는다.
Native Container를 new로 할당할 때, 메모리가 유지되는 시간을 설정할 수 있다.
사용이 끝나면 Dispose()를 사용해 메모리를 해제 해주어야만 한다.
Job의 Schedule를 실행하였을 때 반환되는 값으로, Job을 컨트롤할 수 있는 기능을 가지고 있다.
Job은 독립적으로 실행될 수 있지만, 선행 Job의 실행이 끝난 뒤에 실행해야 하는 경우가 있을 수 있다. 이때 Job Handle을 사용하여 Job의 종속성을 설정할 수 있다.
JobHandle handle_1 = 구조체1.Schedule();
JobHandle handle_2 = 구조체2.Schedule(handle_1);
handle_2.Complete();
handle_2가 handle_1이 끝난 후에 호출된다.
필요한 부분만 사용하고 최대한 피하도록 한다.
사용된 메소드 : Complete();
- Job의 Execute()가 끝날 때 까지 메인 스레드를 대기하도록 만들어준다.
- 메인 스레드에서 Job의 Native Container에 안전하게 접근할 때 사용하면 유용하다.
IJob은 Job에게 작업을 요청할 때, 상속되어야 하는 Interface이다.
Execute()함수는 parameter가 없기 때문에 구조체에 변수를 선언, 값을 넣어 사용해야 한다.
public struct JobStruct : IJob
{
public int a;
public int b;
public NativeArray<int\> result;
public void Exeute()
{
result[0] = a + b;
}
}
void Start()
{
NativeArray<int\> Result = new NativeArray<int\>(1, Allocator.TempJob);
JobStruct job = new JobStruct();
JobStruct.a = 1;
JobStruct.b = 2;
JobStruct.result = Result;
JobHandle handle = job.Schedule();
handle.Complete();
job.result.Dispose();
}
IJob이 단일 스레드에서 Execute()가 처리 되었다면 IJobParallelFor는 사용가능한 모든 스레드에서 Execute()가 병렬로 처리된다.
기본적으로 NativeArray를 사용하여 배열작업을 수행한다.
하나의 Job내에서 배열의 크기만큼 Excute(int)를 호출한다.
Ijob과 구조는 비슷하지만 Execute()에 매개변수가 추가되어있다.
public interface
{
void Execute(int index);
}
매개변수로 전달되는 int는 Execute()메소드 내의 코드를 여러번 반복시켜야할 때, 사용된다.
예를 들면, 다수의 오브젝트에게 동일한 작업을 수행하는 경우 사용된다.
List<GameObject\> list = new List<GameObject\>();
public struct JobStruct : IJobParallelFor
{
public NativeArray<int\> result;
public void Exeute(int index)
{
float temp = list[index];
temp += 1;
list[index] = temp;
}
}
void Start()
{
list.Add(obj1);
list.Add(obj2);
list.Add(obj3);
NativeArray<int\> Result = new NativeArray<int\>(1, Allocator.TempJob);
int batchCount = 1;
JobStruct job = new JobStruct();
JobStruct.result = Result;
JobHandle handle = job.Schedule(list.Count, batchCount);
handle.Complete();
job.result.Dispose();
}