본문 바로가기
Unity • C#

[Unity] Job System 간단 매뉴얼

by SAENS 2024. 1. 3.

자세한 개념은 대부분 생략하고, Job System의 사용법을 예제와 함께 간단히 설명드리려 합니다.

1. 사용 순서

  1. 작업을 Job으로 만들기
  2. Job 인스턴스 생성
  3. Job 인스턴스의 Schedule() 메서드를 통해 JobHandle 객체 생성
  4. JobHandle 인스턴스의 Complete() 메서드를 통해 스케줄된 Job을 실행

2. 예제

(1) IJob
아래와 같이 IJob 인터페이스를 구현하는 형태로 만들어 실행할 수 있습니다.

using Unity.Collections;
using Unity.Jobs;
using UnityEngine;

public class MyMono : MonoBehaviour
{
    public int arraySize = 100;
    void Start()
    {
    	MyJob job = new MyJob() {
            a = 2,
            arr = new NativeArray<int>(arraySize, Allocator.TempJob)
        };

        JobHandle jobHandle = job.Schedule();
        jobHandle.Complete();

        job.arr.Dispose();
    }
}

struct MyJob : IJob
{
    public int a;
    public NativeArray<int> arr;

    public void Execute()
    {
        for(int i=0 ; i<arr.Length ; ++i) arr[i] = a;
    }
}

 
(2) IJobParallelFor
작업이 완전히 반복문만 있으며 인덱스 i에 대해 배열의 i 인덱스에만 접근한다면 IJobParallelFor 인터페이스를 구현해서 반복문을 일정 단위로 끊어서 자동으로 병렬화할 수 있습니다. 만약 배열의 i가 아닌 다른 인덱스에 접근하려 한다면 에러가 납니다.

using Unity.Collections;
using Unity.Jobs;
using UnityEngine;

public class MyMonoParallel : MonoBehaviour
{
    public int arraySize = 100;
    void Start()
    {
    	MyJobParalllel job = new MyJobParalllel() {
            a = 2,
            arr = new NativeArray<int>(arraySize, Allocator.TempJob)
        };

        JobHandle jobHandle = job.Schedule(arraySize, 25);
        jobHandle.Complete();

        job.arr.Dispose();
    }
}

struct MyJobParalllel : IJobParallelFor
{
    public int a;
    public NativeArray<int> arr;

    public void Execute(int i)
    {
        arr[i] = a;
        // if(i > 0) arr[i-1] -= 1; // ERROR
    }
}

IJobParrallelFor 구조체의 Schedule 메서드에는 두 개의 파라미터가 필요합니다. 첫번째는 반복할 횟수(=다룰 배열의 크기, arrayLength)이고, 두번째는 스레드 하나에 할당할 반복 묶음의 개수(batchCount)입니다. 위 코드에서 (100, 25)로 호출했으니, 100번의 작업이 25개 단위로, 즉 4묶음으로 나뉘어져 스레드에 할당되어 병렬처리됩니다. 만약 batchCount가 arrayLength보다 크다면, 에러는 나지 않지만 하나의 스레드로 처리될 것이기 때문에 IJobParallelFor를 사용하는 의미가 없어집니다.

(3) CombineDependencies
JobHandle의 전역 메서드, CombineDependencies()를 통해 여러 JobHandle을 병렬실행할 수 있습니다. 하나의 메서드로 총 세 개까지 combine할 수 있지만, 한 번 combine한 JobHandle을 또 다시 다른 JobHandle과 combine할 수 있으니, Job이 몇개이든지 상관 없이 병렬처리할 수 있겠죠.

using Unity.Collections;
using Unity.Jobs;
using UnityEngine;

public class MyMonoCombine : MonoBehaviour
{
    public int arraySize = 100;
    void Start()
    {
    	MyJob job1 = new MyJob() {
            a = 1,
            arr = new NativeArray<int>(arraySize, Allocator.TempJob)
        };
        JobHandle jobHandle1 = job1.Schedule();

        MyJob job2 = new MyJob() {
            a = 2,
            arr = new NativeArray<int>(arraySize, Allocator.TempJob)
        };
        JobHandle jobHandle2 = job2.Schedule();

        YourJob job3 = new YourJob() {
            a = 3,
            arr = new NativeArray<int>(arraySize, Allocator.TempJob)
        };
        JobHandle jobHandle3 = job3.Schedule(arraySize, 4);

        JobHandle combinedJobHandle = JobHandle.CombineDependencies(jobHandle1, jobHandle2, jobHandle1);
        JobHandle allCombinedJobHandle = JobHandle.CombineDependencies(combinedJobHandle, jobHandle3);

        allCombinedJobHandle.Complete();

        job1.arr.Dispose();
        job2.arr.Dispose();
        job3.arr.Dispose();
    }
}

struct MyJob : IJob
{
    public int a;
    public NativeArray<int> arr;

    public void Execute()
    {
        for(int i=0 ; i<arr.Length ; ++i) arr[i] = a;
    }
}
struct YourJob : IJobParallelFor
{
    public int a;
    public NativeArray<int> arr;

    public void Execute(int i)
    {
        arr[i] = a;
    }
}

댓글