CPU-bound vs IO-bound

제 개인적인 특징인지는 모르겠지만, 개발하다보면 자연스럽게 performance를 어떻게든 최대로 뽑아내고 싶게 됩니다.. ㅎㅎ 그러다보면 자연스럽게 알게되고 사용하게 되는 것이 multithreading 입니다.

Multithreading이란 한 process안에서 여러개의 thread를 만들어서 task를 진행하는 개념이죠. 멀티코어의 세상에서 꼭 필요한 parallel computing의 기본 방법이라고 할 수 있습니다.

하지만 multithreading이 만병통치약은 아닙니다. 저도 이번에 일하면서 알게 되었는데, 해당 task가 CPU-bound인지, IO-bound인지가 매우 중요합니다.

  • CPU-bound : Task가 대부분 cpu power를 사용해야 하는 경우를 말합니다. 예를들면 machine learning model의 경우 대부분 수학 계산을 해야하기 때문에 cpu를 반드시 사용해야합니다.
  • IO-bound : Task가 전체 걸리는 시간에 비해 cpu idle time이 많은 경우를 말합니다. 다시 말해 cpu가 일을 하고 싶어도 반드시 기다려야만 하는 상황을 말합니다. 예를들면 http request를 보내고 response를 기다리는 경우입니다.

어떻게 보면 CPU-bound는 우리가 책을 읽거나 수업을 듣는 등 active하게 상호작용해야하는 상황을 말한다고 할 수 있고, IO-bound는 햄버거 가게에서 햄버거를 주문하고 햄버거가 나올때까지는 할 일이 없는 뭐 그런 비유를 할 수 있겠습니다.

그렇기 때문에 IO-bound일 경우에는 multithreading을 사용하는 것이 비약적인 성능 향상을 가져오겠지만, CPU-bound일 경우에는 available한 core 수까지만 효과를 보고(이마저도 해당 task가 얼마나 cpu를 많이 사용하는지에 따라 다릅니다.) 그 이상은 성능 향상을 기대하기 어렵습니다.

그래서 병렬처리로 성능 향상할 때 task가 정확히 어떤 일을 하고, 어떤 부분에서 IO-bound가 발생하는지 파악하는 것이 중요합니다.

What’s Static??

이번에 알아볼 프로그래밍 컨셉은 static 입니다. 처음 static의 개념을 배웠을 때는 여러 class instance에서 하나의 count 값을 올리는 예제로 배웠어서, 메모리 기능이 있는 건가보다 생각했었습니다. 하지만 실제로는 전혀 다른 차원의 아주 고급스킬이라는 것을 알게 되었습니다 🙂

먼저 클래스 내에 static으로 선언된 변수나 함수들은 별도의 instance를 생성할 필요가 없습니다.

public class Foo {
  public int bar_normal;
  public static int bar_static;
}

이럴 경우 bar_normal을 접근하기 위해서는 반드시 instance를 생성해야 합니다. 즉,

Foo a = new Foo();
a.bar_normal = 1;

이런식으로 접근해야 하는 것입니다. 반면에, bar_static은 위와같은 방법으로 접근할 수도 있지만, static으로 선언되면 하나의 변수가 결국 모든 class instances에 의해 공유되므로 아래와 같이 사용될 수도 있습니다.

Foo.bar_static = 1;

함수의 경우도 마찬가지입니다. static으로 선언된 함수들은 클래스 이름으로 호출이 가능합니다. Java native library중 하나인 Math라는 클래스를 들여다 보면 확실히 이해할 수 있습니다.

public final class Math {
  public static double sin(double a) {...}
}

sin함수를 호출하기 위해서는 따로 Math instance를 만들 필요 없이 Math.sin(a)를 통해서 함수를 호출할 수 있습니다.

static이 정말 중요한 이유는, 동일한 기능을 하는 함수나, 같은 값이 여러 쓰레드 혹은 작업에 의해서 공유될 때 시간을 많이 잡아먹는 instantitation에 시간을 최소화할 수 있기 때문입니다! 또한 개체를 덜 만들게 되니 garbage collection에도 크게 기여하겠죠?