C# Job System

Job System은 data에 안전하게 접근하면서 멀티 스레딩 코드를 구현할 수 있게 한다.

멀티 스레딩의 문제

일반 Component System은 메인 스레드에서 돈다. 코어 수가 늘어나는 추세에 한 곳에서만 돌게 하는 것은 유용하지 않다. DOTS에 Job Component Systems (JCS)는 Job들을 Worker Thread에서 수행되도록 예약하는 일을 한다. (위 그림 참고)

// 예시

struct CopyFloatsJob : IJob
{
  // Job에서 접근할 data를 모두 선언
  // 안정성을 보장하기위해 읽기 전용 여부 선언
  [ReadOnly]
  public NativeArray<float> src;
  public NativeArray<float> dst;
  float deltaTime;
  
  // Job에서 실행될 코드
  public void Execute()
  {
    for(int i = 0; i < src.Length; i++)
    dst[i] = src[i] * deltaTime;
  }
}

var job = new CopyFloatsJob()
{
  src = new NativeArray<float>(500, Allocator.Temp),
  dst = new NativeArray<float>(500, Allocator.Temp),
  deltaTime = Time.deltaTime
};

아래와 같이 Job이 끝나기 전에 인자를 수정하면 유니티 로그에 에러메시지가 뜬다.

JobHandle jobHandle = job.Schedule();
src[0] = 5;

...

// Complete the job ...

jobHandle.Complete();

다음과 같은 코드는 가능하다.

JobHandle jobHandle = job.Schedule();

...

// Complete the job ...
jobHandle.Complete();

src[0] = 5;

NOTE: NativeContainer

공유 메모리 타입. NativeContainer를 사용하면 잡이 복사본으로 작업하는 것이 아니라 메인 스레드와 공유되는 데이터에 액세스할 수 있다.

NativeContainer 관련 설명은 여기서 확인할 수 있음 here!

 

IJobParalleFor

여러개의 잡을 병렬로 실행할 수 있다.

struct CopyFloatsJobFor : IJobParalleFor
{
  // Job에서 접근할 data를 모두 선언
  // 안정성을 보장하기위해 읽기 전용 여부 선언
  [ReadOnly]
  public NativeArray<float> src;
  public NativeArray<float> dst;

  // Job에서 실행될 코드
  public void Execute(int index)
  {
    dst[index] = src[index];
  }
}

var job = new CopyFloatsJobFor()
{
  src = new NativeArray<float>(500, Allocator.Temp);
  dst = new NativeArray<float>(500, Allocator.Temp);
};

// job을 예약할때 amount of foreach & batch size 를 입력할 수 있다
job.Schedule(500, 100);

 Job이 끝나고 다른 잡을 Schedule할 수 있다

// src -> dst 카피하는 잡 스케줄
var src = new NativeArray<float>(500, Allocator.Temp);
var dst = new NativeArray<float>(500, Allocator.Temp);
var jobA = new CopyFloatJobFor() {src = src; dst = dst};
var jobAHandle = jobA.Schedule(src.Length, 100);

// dst -> finalDst 카피하는 잡 스케줄
var finalDst = new NativeArray<float>(500, Allocator.Temp);
var jobB = new CopyFloatJobFor() {src = dst, dst = finalDst};

// jobAHandle의 dependency로 jobB를 스케줄한다.
var jobBHandle = jobB.Schedule(src.Length, 100, jobAHandle);

jobBHandle.Complete();

여기는 Unite Austin 2017 - Writing High Performance C# Scripts이걸 보고 간단히 정리한 것이라 자세히 보려면 unity manual을 보는 것이 좋을 것 같다.

  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기