CPU 스케줄링 : FCFS, SJF, SRTF

스케줄링이란?
- 컴퓨터 시스템의 모든 자원을 효율적으로 사용하기 위한 프로세스 관리 정책
- 목적 : 컴퓨터 시스템의 성능향상
- 등장 배경 : 다중 프로그래밍을 지원하는 OS(운영체제)에서 프로세서를 효율적으로 관리하기 위해

성능 지표
 - 응답 시간 : 시스템이 사용자의 요구에 응답하는 시간
 - 작업 처리량 : 단위 시간 내의 프로세스 처리량
 - 자원 활용도 : 주어진 기간 동안의 자원의 활용 정도

1. FCFS(First-Come First-Served)
 - 먼저 요청한 프로세스 순으로 스케줄링하는 비선점 방식
 - 장점 : 자원의 효율성 높음, 일괄 처리 시스템 등에 적합
 - 단점 : 평균 응답 시간이 길어질 수 있음(장시간 독점의 경우 다른 프로세스들이 오래 기다려야 함), 대화형 시스템에 부적합

프로세스
도착시간
버스트 시간
P1
0 ms
24 ms
P2
1 ms
3 ms
P3
2 ms
3 ms

P1(24)
P2(3)
P3(3)
평균 대기시간 : (0(P1) + (24-1)(P2) + (27-2)(P3))/3=16ms
평균 반환시간 : (24(P1) + (27-1)(P2) + (30-2)(P3)/3=26ms

2. SJF(Shortest-Job-First)
 - CPU 작업 시간이 가장 짧은 프로세스 순으로 스케줄링하는 비선점 방식
 - 작업 시간이 동일할 경우 FCFS 정책 따름
 - 장점 : 평균 대기 시간 최소화, 시스템 내의 대기 프로세스 수 최소화, 빠른 응답 시간 제공
 - 단점 : 무기한 연기 현상 발생(에이징 기법으로 해결 가능), 프로세스 생성시 총 실행 시간에 대한 정확한 계산 불가능
*에이징 기법(Aging) : 오래 있었던 프로세스일수록 우선순위를 높여주는 방식

프로세스
버스트 시간
P1
6 ms
P2
8 ms
P3
7 ms
P4
3 ms
P4(3)
P1(6)
P3(7)
P2(8)
평균 대기시간 : (0(P4) + 3(P1) + 9(P3) + 16(P2))/4=7ms
평균 반환시간 : (3(P4) + 9(P1) + 16(P3) + 24(P2)/4=13ms

3. SRTF(Shortest-Remaining-Time-First)
 - 선점 SJF 알고리즘 방식
 - 장점 : 평균 대기 시간 최소화
 - 단점 : 프로세스 생성시 총 실행시간 추정 작업 필요, 오버헤드 증대, 실행 시간이 긴 프로세스들의 평균 응답 시간 길어짐
 - 구현 및 사용이 비현실적인 알고리즘 방식
* 오버헤드 : 프로세스와 프로세스 간 교차할 때 생기는 틈
프로세스
도착시간
버스트 시간
P1
0 ms
8 ms
P2
1 ms
4 ms
P3
2 ms
9 ms
P4
3 ms
5 ms
P1(1)
P2(4)
P4(5)
P1(7)
P3(9)
평균 대기시간 : (9(P1) + (1-1)(P2) + (5-3)(P4) + (17-2)(P3))/4=6.5ms
평균 반환시간 : (17(P1) + (5-1)(P2) + (10-3)(P4) + (26-2)(P3)/4=13ms


*SJF와 차이점
- SJF
 - 중간에 버스트 시간이 더 짧은 것이 들어와도 비선점이라서 실행하지 못함
P1(8)
P2(4)
P4(5)
P3(9)
평균 대기시간 : (0(P1) + (8-1)(P2) + (12-3)(P4) + (17-2)(P3))/4=7.75ms
평균 반환시간 : (8(P1) + (12-1)(P2) + (17-3)(P4) + (26-2)(P3)/4=14.25ms

SJF보다 SRTF가 이론상 더 빠름
But, 오버헤드로 인하여서 사실상 구현이 불가능

댓글

  1. 스칼라 제 3장 함수



    스칼라의 함수

    함수형 프로그래밍인 스칼라에서는 함수 자체를 전달하고 반환받을 수 있다.

    스칼라에서 함수는 필요하다면 언제든지 =>로 표현되는 식을 통해 객체처럼 행동할 수 있





    함수 정의

    스칼라는 함수를 def 예약어를 통해 만들 수 있는 함수는 기존의 프로그래밍 언어와 크게 다르지 않은 문법을 가지고 있다

    def 함수명([매개변수]): [반환 자료형] = {

    // 구현할 로직

    }

    변수와 마찬가지로 함수도: 을 이용해 반환 자료형을 뒤에 표시한다 이는 함수의 반환 자료형이 함수의 자료형을 결정한다는 뜻이다 즉, 변수와 근본적으로 다를 것이 없다는 생각을 전제로 한다

    def main(agrs: Array[String]): Unit = {

    println("Hello Scala")

    }

    앞에서 계속 보았던 기본적이 메인 함수이다 Unit는 반환 결과가 없는 함수에 붙는 자료형을 말한다

    스칼라에서는 반환 값이 있을 때에도 반환 자료형을 생략하는 것이 가능하다

    코드: 반환자료형을 명시적으로 선언하지 않은 함수

    object Ex 5_1{

    def main(agrs: Array[String]) = {

    println("반환받은 값" + name()

    }

    def name () = {

    val a = 10

    a

    }

    결과

    반환받은 값: 10

    반환 자료형을 명시하지 않아 오류가 날 듯 한데 잘 작동한다

    return a라고 명시적으로 쓰지 않아도 알아서 반환하는 것이다 물론 명시적으로 return 을 쓸 수도 있다 그러려면 함수 선언하는 곳에도 반환 자료형을 명시해야한다

    반환해야하는 자료형이 확실할 때 또는 가독성을 고려하거나 에러를 방지하기 위해서 필요한 경우에만 반환 자료형을 명시한다

    예제: 간단한 덧셈을 하는 함수

    object Ex 5_2{

    def main(agrs: Array[String]) = {

    val result = sum(1, 2)

    println(result)

    }

    def sum (a: Int, b:Int): Int = {

    a + b

    }



    [코드 5_2]는 다음과 같이 대괄호를 생략하고 한주로도 표현이 가능하다

    def sum(a: Int, b: Int): Int = a + b



    CALL-BY-NAME

    보통 함수는 두 가지 형태로 호출할 수 있다 CALL-BY-VALUE(값으로 호출)

    CALL-BY-NAME(이름으로 호출) 두가지이다

    CALL-BY-VALUE는 많이 봤던 함수이다 예를들어 a(b(x))처럼 중첩된 형태로 함수를 호출하면 안쪽을 함수 b가 반환하는 값이 다시 함수 a 에 들어가지는 식으로 코드가 동작한다

    CALL-BY-NAME 는 b자체가 a의 인수로 들어간다고 생각하면 된다 b에 고초 넝ㅎㄴ 겂아 어나느 b 라는 함수 자체를 매개변수로 인정하는 것이다

    코드 5_3 드랍십에 사람을 태우는 코드

    object Ex 5_3 {

    def main(agrs: Array[String]): Unit = {

    dropship(people(5))

    }

    def people(n: Int) = {

    println("탑승수속을 시작합니다")

    n

    }

    def dropship(n: Int) = {

    println("드랍십 준비합니다")

    println(n + "명 탑승했습니다")

    }

    }

    결과 5_3

    탑승수속을 시작합니다

    드랍십을 준비합니다

    5명 탑승했습니다

    이와 다르게 함수의 인수를 받는 방법을 =>으로 바꿀 수 있다

    코드 5_4 =>형식의 함수를 이용한 코드

    object Ex 5_4 {

    def main(agrs: Array[String]): Unit = {

    dropship(people(5))

    }

    def people(n: Int) = {

    println("탑승수속을 시작합니다")

    n

    }

    def dropship(n: => Int) = {

    println("드랍십 준비합니다")

    println(n + "명 탑승했습니다")

    }

    }

    결과 5_4

    탑승수속을 시작합니다

    드랍십을 준비합니다

    5명 탑승했습니다

    즉 dropship(n: Int)가 아닌, dropship(n: =>Int) 와 같이 쓰면 바깥에 있는 함수 먼저 실행 했다가 매개변수가 필요할 때 그것을 사용할 수 있다 =>를 상요하는 이러한 방식이 바로

    CALL-BY-NAME방식이다

    스칼라에서 CALL-BY-NAME으로 호출되는 함수는, 호출하는 함수가 매개변수를 필요로 할 대마다 계속 부름을 당한다 즉, 일반적인 경우에서처럼 호출되는 함수의 결과값이 호출하는 함수에 전달이 되는 것이 아니라 호출되는 함수의 코드 자체가 하나의 함수 자체가 매개변수로 전달되기 때문에 위와 같은 결과가 나오는 것이다

    코드에서=>가 보인다면 그서은 단순한 함수의 표현 형식이 아니다 처음에 이야기를 했던 것 처럼 '표현 형식' 보다는 하나의 '객체'라고 보아야한다

    답글삭제
  2. 함수의 일부 인수 고정하기(부분 적용 함수)

    부분 적용함수는 말로 설명 하기는 어렵기 때문에 코드부터 보면서 기능을 확인하겠습니다

    코드 5_5 매개변수에 기본값을 설정

    object Ex 5_5 {

    def main(agrs: Array[String]): Unit = {

    val thisYear = 2016



    //아직 인수가 존재하지 않지만,

    // _ 와일드카드를 사용해 어느 String 값이든 들어올 수 있다고 선언

    val fixedValueFunction = go(thisYear, _:String)

    //go()가 아니라 fixedValueFunction 형태로 호출



    fixedValueFunction("test1")

    fixedValueFunction("test2")

    fixedValueFunction("test3")

    }

    def go(thisYear: Int, string: String) = {

    println(string + ":" + thisYear)

    }

    }

    결과 5_5

    test1: 2016

    test2: 2016

    test3: 2016

    매개변수 중 하나는 별로교체할 필요가 없거나 계속 같은 값을 집어넣어야 하는 경우 같은 코드를 쓰는것은 효율이 떨어질 수 있다 이럴 때는 위와 같이 변수로 선언된 함수에 먼저 넣을 인수를 집어넣고 계속 변해야 하는 인수는 언더바(_)를 이용해서 자료형만 정해주면된다



    Tip 커링을 이용한 부분 적용 함수

    커링은 부분 적용 함수를 만들 때 쉽게 쓰일 수 있다 예를 들어 두 수의 합계를 구하는 함수를 생각해 볼때 일반 함수는 다음 코드처럼 여러 개의 인수를 받았지만, 커링 힘수는 하나의 인수를 받으면서 여러 개의 함수가 중첩된 형태를 띈다

    def normalSum(x: Int, y: Int) = x + y

    def curriedSum(x: Int)(y: Int) = x + y



    *커링: 여러 개의 인수를 받는 하나의 함수를 하나의 인수를 받는 여러 개의 함수로 바꿔주는 기법을 말한다



    5.6 =>를 이용한 함수 표현식

    =>는 매개변수로 함수를 넘길 수 있다

    def functionExpression(x: (Int => Int)) = {\\..}

    또한 함수를 객체처럼 사용하게 해준다

    val functionAsValue = (y: Int) => y + 10



    5.7 매개변수가 여러개인 함수

    스칼라는 매개변수가 여러 개 이더라도 매개변수를 받을 수 있다

    object Ex 5_7 {

    def main(agrs: Array[String]): Unit = {

    printlnStrings("string1", "string2", "string3");

    }



    def printlnStrings(args: String*) = {

    for (arg <- args) {

    println(arg);

    }

    }

    }

    결과 5_7

    string1
    string2

    string3

    위의 코드를 통해 String* 이라는 표현으로 여러 개의 String을 받을 수 있다는 것을 알 수 있다



    5.8 매개변수의 기본값 설정

    object Ex 5_8 {

    def main(agrs: Array[String]): Unit = {

    println("기본값은" + default())

    }

    def default(a: Int = 4, b: Int = 5): Int = a + b

    }

    결과

    기본값은 9

    위에 보다시피 스칼라는 자체적으로 함수 매개변수의 기본값을 설정 해줄 수 있다

    위 코드는 default를 호출하면서 매개변수를 주지 않았다 보통의 경우 매개변수가 없다고 에러가 났을 것이다 하지만 이 코드처럼 함수를 정의 할 때 기본값을 설정하면 에러가 나지 않고 기본값을 넣어 반환해준다



    5.9 apply()

    apply() 메서드는 변수를 받아 함수에 적용시켜 결과를 만들어 내는 일종의 설정자와 같은 역활을 한다 즉 함수 f(x) = x같은 함수가 있을 때 x를 설정하는 기능이라고 할 수 있다

    코드5_9 apply() 메서드 이용하기

    object Ex 5_9 {

    class SomeClass {

    def apply(m: Int) = method(m)

    def method(i: Int) = i + i

    def method2(s: String) = s

    }

    def main(agrs: Array[String]): Unit = {

    val something = new SomeClass



    println(something(2))

    }

    }

    결과 5_9

    4



    5.10 implicit 함수

    implicit는 말 그대로 묵시적으로 함수를 표현한다는 말이다

    코드를 보며 이해를 해보자

    def doubleToInt(d: double) = d.toInt

    val x: Int = doubleToInt(18.0)

    이 코드는 double를 받아 Int 형으로 바꾸어 주고 x에 Int를 받는 것이다

    만약 코드를 이렇게 한다면 어떻게 될까?

    def doubleToInt(d: double) = d.toInt

    val x Int = 18.0

    type mismatch; found : Double(18.0) required: Int

    이렇게 코드를 짜면 위 같은 오류가 날것이다 이때 implicit를 선언해준다면 에러를 바로 내지 않고 해당하는 함수가 있으면 그것을 사용해 암묵적으로 형 변환을 하도록 도와주어 함수의 활용도를 높이 겠다는 뜻이다 하지만 반환자료형으로 컴파일러가 알아서 판단하기 때문에 위험이 어느 정도 있는건 확실하다.

    만약 다음과 같이 implicit으로 선언된 함수가 여러 개이고 그 여러개가 반환 자료형과 매개변수 자료형이 같다면 어떻게 될까?

    implicit def doubleToInt(d: Double) = d.toInt

    implicit def doubleToInt2(d: Double) = d.toInt + 1

    val x:Int = 18.0

    이 상황인 경우 컴파일러가 어떤 것을 선택할지 알아서 판단할 수 없으므로 경고 메세지와 함께 컴파일이 되지 않을 것이다 그 내용은 모호해서 컴파일러가 판단할 수 없다는 것이 핵심이다 implicit함수는 맥락을 파악하기 떄문에 길게 늘여 써야만 하는 코드를 상당히 줄여줄 수 있지만 위험성이 있는 것은 감수해야 한다



    Tip 함수와 메서드의 차이

    함수는 메서드를 아우르는 용어로서, 객체지향 프로그래밍에서 메서드는 객체나 클래스 내부에 선언되어 하나의 기능을 하는 함수를 뜻한다 즉 함수안에 메서드가 작동하는 것을 말한다 다만, 스칼라에서는 하나의 기능 단위가 객체나 클래스에 속하지 않는 경우가 있다 =>를 아용한 함수 표현식은 그 자체가 함수 기능을 하지만, 어떤 객체나 클래스에 속해서 기능을 담당하는 것은 아니다

    답글삭제

댓글 쓰기