이전에 들었던 수업은 하드웨어를 이용한 동기화 시스템에 대해서 이야기 하였다.

test_and_set()과 compare_and_swap()에 관련된 시스템 콜 기반 Critical Section을 활용한 동기화 Solution에 대해서 말이다.


이번에 배운 것은 하드웨어 동기화 Solution이다.


그 첫번째

Mutex Locks(=Mutual Exclusion Lock)


Mutex Lock에는 두 가지 함수가 존재한다.

Lock을 차지하는 acquire()과 Lock을 놓아주는 release()


두 함수가 어떻게 description되어 있는지를 확인하면


   -> description

이렇게 구성이 되어있다.

코드를 보면 구성이 매우 심플하다 ㅎㅎ


물론 위의 코드는 소프트웨어적으로 처리하는 것이 아닌, 하드웨어적으로 처리하게 된다.

(acquire과 release는 무조건 atomic해야 하기 때문이다.)


하지만 위의 함수에서 가장 큰 Issue가 있는데, 바로 busy_waiting이다.

고가의 cpu를 열심히 돌리는데... 결과론적으로, waiting이라니... 이 얼마나 낭비인가.(spinlock이라고도 불린다.)


이러한 문제에 대한 해결책은 다음장에서 배운다고 하니 일단 넘어가자.


다음으로 배운 것은

semaphore이다.


semaphore의 기원을 한 번 알아보자.


semaphore를 인터넷에 검색하니깐 이러한 그림이 나왔다.

이 그림은 무엇일까...?

바로 빨간색 네모 박스를 의미한다.

저 기찻길 신호등과 기찻길 사이의 공간에는 기차와 차 또는 사람이 같이 들어갈 수 없다. semaphore도 어떠한 자원을 여러명이서 차지할 수 없다는 뜻에서 이름을 이렇게 지었나보다.


각설하고 semaphore를 조금 더 자세히 들여다 보면, Lock과 달리 S라는 variable이 존재한다. 이는 가용 자원수로서 해당 자원을 몇 명의 사람이 사용할 수 있는지를 결정한다.


예를 들어 학교에 학생들을 프로세스, 체육 선생을 semaphore라고 하고, 축구공을 공유자원이라고 하자.

체육 선생이 축구공을 4개 가지고 있다면 S = 4가 되는 것이고, 이는 4개의 process가 각각 사용할 수 있는 것이다.


이 S 변수는 학생이 축구공을 소지하면 개수가 감소하고(S--) 다시 돌려주면 개수가 증가한다(S++)

그리고 전자의 과정을 wait(), 후자를 signal()이라고 한다.

Mutex Lock에서 acquire()과 release()와 동일한 기능을 수행한다.

그리고 어떠한 책에서는 P(), V()라고도 표현하는데 다 같은 의미라고 보면 되겠다.


무튼 wait()와 signal() 함수는 아래와 같은 동작을 수행한다.


S가 0이하라면 semaphore의 공유 자원의 개수가 없는 것이므로 대기한다.

그렇지 않다면 S--를 수행해 가용 자원수를 감소시킨다.

signal()은 자원을 돌려놓는 것이므로 가용 자원수를 증가시킨다.


semaphore의 종류는 크게 2가지 입니다.

* Counting semaphore

- S > 1

* Binary Semaphore

- S == 1

- Binary Semaphore는 Mutex Lock과 동일한 역할을 수행한다고 보면 된다.


기본적으로 Semaphore는 다양한 사용법이 있는데 그 중 하나

1. P1의 S1 다음에 P2의 S2를 수행하고 싶은 경우


위의 코드를 한 번 보자.

synch = 0으로 초기화한다고 가정한다.

wait() 함수의 경우 parameter가 0일 경우 대기하게 되고,

signal()함수는 S1작업이 모두 끝나게 되면  호출되어 synch++을 수행하게 될 것이다.

이렇게 하면 자연스럽게 각 Process 간에서의 동작도 수행 순서를 설정할 수 있게 된다.


하지만 이 semaphore도 문제가 있다. 바로 busy_waiting 문제!!!


busy_waiting을 해결하기 위해서는 Process의 Waiting 상태(=Blocked)를 이용하는 것이다.

이와 관련된 list를 하나 생성하고, wait가 필요하다면 list에 push후 block시킨다. - (1)번

그리고 조건을 만족하면 list에서 process를 pop하고 wakeup 시킨다. - (2)번


        










그렇게 변경된 wait()와 signal() 함수.

semaphore라는 구조체가 하나 생성이 되었고, 해당 구조체는 value(=S), list(=wait_list) 두 개의 인자를 가진다.


wait() 함수가 호출되면 이전처럼 busy_waiting 후 가용 자원수를 감소시키는 것이 아닌, 일단 가용 자원수(value)를 감소시킨 후 해당 자원수가 음수일 경우 대기해야 하므로, list에 해당 process를 push한 후 block()시킨다.


signal() 함수의 경우 가용자원수를 다시 늘리는 작업 뿐만 아니라, list에 process가 들어가 있을 경우(S->value <= 0을 만족하는 경우) list에 있는 process를 제거시켜주고, 해당 process(현재 process가 아님)를 깨운다.


Ex)

A라는 process에서 wait()를 호출하고, B라는 process에서 wait()를 호출하였고, semaphore의 value는 1이라고 가정해보자.


A라는 process에서 wait()를 호출하게 되면, semaphore->value는 0이 되고, critical section에 들어가서 필요한 작업을 수행하게 될 것이다. 그 사이에 B Process에서 wait()를 호출하게 되면 B Process는 block 상태에 들어가게 될 것이다.

그 후 A process의 Critical Section에서 모든 작업이 종료되고, signal()을 수행하게 되면 list에 들어있던 B process를 꺼내 wakeup(=unblock)을 수행하게 될 것이다.

그렇게 B process wait()이후부터 동작을 수행하게 될 것이고 critical section 작업을 수행할 것이며 그 당시 semaphore->value는 0을 유지하고 있을 것이다.



자 이제 이렇게 동기화 작업 사이에서 발생할 수 있는 문제점들에 대해서 한 번 이야기를 해보자.


이야기할 문제는 크게 3가지가 있다.

1. Deadlock

* 두 개 이상의 Process가 서로를 기다림으로써 발생하는 문제. Program이 멈춰버리게 된다.

2. Starvation

* Priority 등에 의해서 어느 하나의 process가 동작하지 못하고 굶어 죽는 현상

3. Priority Inversion

* 이 역시 priority에 의해서 더 낮은 process가 더 높은 process보다 먼저 수행되는 현상.

* 이 현상은 priority-inheritance protocol을 이용하여 해결할 수 있다.


위에서 언급한 문제들을 일반화시켜 설명해보려 한다.


1. Bounded-Buffer Problem


Bounded-Buffer Problem은 Producer-Consumer 사이에서 발생할 수 있는 문제이고, semaphore를 이용하여 해결할 수 있다.

Producer

 Consumer

 

 


여기서는 value가 3종류가 사용되었다.

semaphore empty

semaphore full

semaphore mutex

n개의 buffer가 있다고 가정하였을 때

mutex = 1, full = 0, empty = n으로 초기화를 수행한다.



Producer는 Buffer에 데이터가 꽉 차 있을 경우에는 기다려야 한다.

코드를 보면 가장 먼저 wait(empty)를 수행하게 되는데, wait() 함수는 parameter 값을 일단 감소시키고, 감소된 결과 값이 0 미만일 경우 대기하게 된다. 따라서 empty < 0일 경우는(=Buffer에 빈자리가 없을 경우 = Buffer가 꽉찬 경우) wait를 수행하고, 그렇지 않을 경우는 wait(mutex)를 지나 buffer에 값을 쓰기 시작한다.(=buffer에 값을 넣거나 빼는 행위는 atomic하게 수행되어야 한다.)

writing 과정이 모두 끝나면, signal()을 이용하여 mutex에 대한 lock을 해제해주고, full에 대한 lock 역시 해제한다.

signal() 함수는 가용 자원수를 증가시키는 역할을 수행한다. 즉, full이 0이라는 의미는 현재 Buffer에 사용가능한 데이터가 없다는 의미=사용할 수 있는 데이터가 없다는 것이다.


이러한 맥락에서 Consumer도 쉽게 해석이 되리라 생각된다.



2. Reader- Writers Problem


이번에는 읽는 사람과 쓰는 사람간의 문제이다.

읽는 사람은 누가와서 읽어도 상관없지만, 쓰는 사람은 그 순간에는 최대 1명이 되어야 한다.


이러한 동작을 위해서 3개의 변수가 사용된다.

semaphore rw_mutex = 1

semaphore mutex = 1

int read_count = 0


그리고 Reader-Writers Problem에서는 문제를 해결하기 전에 다양한 가정을 산정지을 수 있다.

(1) writer가 공유 자원에 대한 권한을 가지고 있지 않다면, reader는 waiting할 필요가 없다.


(2) writer가 준비가 되면 바로 writing을 수행해야 한다.


이 두 가지 경우 모두 starvation이 발생할 수 있다.

이번 수업에서는 (1)의 경우에 대해서만 코드를 확인해 보았다.


writer 

 reader

 

 


writer는 간단하다. 읽고 쓰는 사람이 없으면 들어가서 쓰면 된다.

reader의 경우는 살짝 복잡하다.

read_count라는 변수를 증가시키기 위해 mutex semaphore를 이용하여, 다른 process가 실행되지 못하게 하고, count를 증가시킨다. 만약, read count == 1이라면 가장 먼저 공유 자원을 읽으려는 process이므로, 혹여 writer가 있나 없나를 체크 하고 없다면 signal()을 이용해 read_count에 대한 critical section을 종료한다.

이렇게 되면 현재 rw_mutex = 0인 상태이기 때문에 writer는 접근을 할 수 없다. 하지만 다른 reader들은 얼마든지 접근이 가능하다.

read가 다 끝났으면 다시 read_count를 감소시켜주기 위해 wait(mutex)를 실행하고, read count--를 수행한다.

만약 read count가 0이라면, 읽는 사람이 없다는 뜻이므로, rw_mutex를 증가시킨다.


이렇게 하면 reader writer problem의 (1)번 경우가 해결된다.



3. Dining Philosophers Problem


해당 그림에서 5명의 사람(Process)가 있고, 5개의 젓가락(Shared resource)가 있다. 그리고 하나의 프로세스는 자신의 양 옆에 있는 두 개의 젓가락을 사용할 수 있다.


여기서 발생할 수 있는 문제는 바로 DeadLock이다.


이러한 코드가 있다고 가정해보자.

각각 따로 실행이 잘 된다면 문제가 없을 것이다. 하지만 5개의 process가 동시에 젓가락을 탐한다고 해보자.
만약 모두가 왼쪽 젓가락을 원했다. 그래서 왼쪽 젓가락을 사용할 수 있는 것을 확인하고, 오른쪽 젓가락을 확인해보니 모든 젓가락이 사용중인 것이다. 이렇게 되면 각 Process가 서로서로를 기다리게 되고, 결과적으로 시스템이 멈춰버리는 DeadLock 문제가 발생하게 된다.

오늘 배운 것은 바로 여기까지~






















이번 수업에서는 Machine-Independent Loader Features. 즉, 기계에 독립적인 Loader의 특징에 대해서 공부해보려 한다.


Automatic library search

자동적으로 외부의 reference를 관리하는 방식.

이러한 linking과 loading의 옵션

: 대체할 소스를 입력시킬 수 있다 - INCLUDE

: 외부 참조를 변경하거나, 제거할 수 있다 - DELETE, CHANGE

: 외부 참조의 자동 처리를 조절할 수 있다...?


목표

loaded된 프로그램에 subprogram의 routines들을 자동적으로 통합시키는 것


<실행 순서>

Linkage Loader

* 참조되었지만 정의되지 않은 외부 심볼들을 계속적으로 추적해야 한다. [ESTAB(=External Symbol TABle)을 이용하여]

* Pass 1 마지막에 undefined된 심볼이 존재한다면 "unresolved"라고 명명한다.

* Loader는 unresolved된 심볼에 대해서 library들을 검사한다.

  -> 기존에는 단순히 에러를 리턴하였다.

* 모든 unresolved 심볼의 정의를 찾을 때까지 라이브러리를 계속 search한다.


Automatic Library Search에 대한 추가적인 discussion

* linking loader는 override가 가능하다.

* linking loader가 모든 object program의 Define record를 탐색하는 과정에서 Directory(=계층적으로 자료를 저장) 하면 더욱 효율적으로 탐색을 수행할 수 있다. -> data


Loder Option

* User가 직접 지시하여 기존의 processing을 수정할 수 있는 것.

INCLUDE : 라이브러리를 포함시키는 것

DELETE : 심볼을 삭제시키는 것

CHANGE : 심볼을 바꾸는 것

LIBRARY MYLIB : 사용자가 만든 라이브러리를 먼저 탐색하는 것(General함)

NOCALL : 심볼을 unresolved 상태로 남겨놓는 것



Loader Design Option


Linking Loader와 Linkage Editor

Linking Loader

 Linkage editor

* 모든 linking과 relocation을 수행한다.

* automatic library search를 포함하고,

프로그램의 실행을 위해 메모리에 link된 프로그램을 load한다.


* 거의 모든 Program 과정에서 reassembled되는 것

= 계속 바뀌는 것. (인풋 아웃풋을 이야기하는 것이 아님)

ex) 프로그램 개발 과정, 테스트 환경 같은 것들은 개발을 수행하면서 프로그램의 알고리즘이 계속 바뀌게 되므로 계속 reassemble을 수행해줘야 함.

 * 나중에 실행하기 위해 프로그램의 link된 버전을 생산한다.


* reassemble할 필요 없이 많이 실행 되는 것.

 = standard library. 이는 우리가 계속 바꾸지 않음.

  


Linkage Editor는 Dynamic Linking을 수행하기 위해서 사용됨.


Dynamic Linking이란?

* Runtime 과정에서 Dynamic Loader에 의해 필요한 부분이 Memory에 적재되는 것.

ex) Exception Handler




잡담


탐색기의 불편한 점... 다운로드의 불편한 점... XML... URI.... Rule Engine....


윈도우의 탐색기는 과거나 지금이나 변한 것이 하나도 없다.

현재 윈도우의 탐색기는 탐색을 전적으로 User가 책임져야 한다.

탐색기는 단순히 탐색을 수행할 수 있게 도와주는 것이 아니라 각 파일 간의 relation을 형성하여, 하나의 파일을 실행시켰을 때 해당 파일과 연관된 다양한 파일 또는 URL들을 띄워줌으로써 과거에 수행했던 작업을 계속적으로 수행할 수 있게 도와주면 정말 좋을듯 하다. -> 특허 등록 상태 ㅎㅎ


다운로드는 어디서 다운로드를 받았는지 URL을 tag 형태로 저장해놓으면 정말 좋을 거 같은데 그러한 기능이 없음.


AI는 relation을 만드는 학문. 이러한 relation은 Rule engine을 이용하여 만들 수 있음. 아주 강력한 도구.

Rule-engine은 사람이 concurrent하게 일할 수 있게 해줌.





컴퓨터 관련 분야에서 가장 중요한 것은 영어다.


격언 : 컴퓨터를 잘하는 사람에게 영어를 가르치는 것보다 영어를 잘하는 사람한테 컴퓨터를 가르치는 것이 더 낫다.

자신의 의견을 어필하기 위한 수단이 영어다.


영어 공부 열씨미 하즈아아


각설하고, Synchronization에 대해서 오늘은 공부하였다.


동기화 문제가 발생하는 이유는 바로 일관성(consistency)가 깨지기 때문이다. 만약 하나의 코어에서 하나의 process만 동작한다면 동기화가 필요 없겠지만, 다양한 process가 다양한 코어에서 사용되다 보니 일관성이 깨져 동기화 문제가 발생하게 되는 것...


이러한 문제를 해결하기 위한 방법으로 소프트웨어적인 방법과 하드웨어적인 방법 크게 두 가지가 존재한다.





아, 문제 해결 방법을 정리하기 전에 동기화 문제에 대해서 예시를 한 번 들어보자.


자, 예전에 공부했던 Producer-Consumer Problem에서 우리는 circular queue를 구현하여, 버퍼를 만들어 사용하였다. 이 때 empty와 full을 구분하기 위해 귀중한 buffer 하나를 사용하지 않으면서 말이다.


그런데 한가지 궁금증이 생긴다. 그냥 counter라는 공유 변수를 놓고 버퍼가 차면 하나 증가시키고, 버퍼가 빠지면 하나 감소시키면서 관리하면 되지 않는가?


여기서, 동기화 문제가 발생한다. HLL(=High Level Language)에서 한 줄은 실제 여러줄로 동작될 수 있다.


예를 들어, counter++ 이라는 명령어를 실제로 instruction set 단계로 내려가면

register1 = counter (LOAD)

register1 = register1 + 1 (ALU)

counter = register1 (STORE)

3가지 단계를 거치게 된다.


그런데 이 때 Race Condition이라는 문제가 발생하게 된다.


Race Condition이란?

한국 말로 "경쟁 상태"로서 둘 이상의 입력 또는 조작의 타이밍이나 순서 등이 결과값에 영향을 줄 수 있는 상태를 말한다.

- 위키

즉, 실행 순서에 따라서 결과가 다르게 나올 수 있다는 것이다. 말이 되는가? counter++을 했는데 결과가 2개 이상이 나올 수 있는 경우가 있다는 것이?????!!!!!!


결론은 가능하다!


자 예를 한 번 들어보자.


2개의 Process가 존재하고, 각 Process에서 counter++, counter--를 수행해보자.

각 명령은 3개의 instruction set으로 존재하고, 하나의 instruction이 atomic한 경우를 만족한다고 가정하면, context-switching은 instruction과 instruction 사이에서 발생할 수 있을 것이다.


만약 counter++, counter--를 수행하게 되면 초기값이 5였을 때 최종 결과는 항상 5가 되어야 하는데...

register1 = counter

register1 = register+1

------------------------------> context-switching 발생

register2 = counter

register2 = register -1

------------------------------> context-switching 발생

counter = register1

------------------------------> context-switching 발생

counter = register2

위의 과정을 거치면 counter 값은 4가 된다.

위와 같은 경우로 인해 우리는 circular queue에 두 개의 variable을 두고 Producer와 Consumer가 건드릴 수 있는 variable을 각각 설정한 것이다.(이는 공유 자원이 아니다!)



어떠한 이유로 동기화 문제가 발생하는 것을 알았으니, 어떻게 하면 이러한 문제가 발생하지 않을까?


"하나의 Process가 공유 자원을 사용하면 다른 Process는 공유 자원에 접근할 수 없다"

로 해결할 수 있을 것 같다.



좀 더 자세하게 들어가보자.


운영체제에서는 Cirtical Section Problem이라는 것이 있다.


Critical Section(<->remainder section)이란 상호 베타적인 접근을 보장해주는 영역으로서 각 Process마다 Critical Section을 가지고 있고, 어떠한 Process가 Critical Section에서 작업하고 있다면 다른 Process는 Critical Section에서 작업을 할 수 없는 것이다.

Problem은 어떻게 상호 베타적인 접근을 보장해주냐는 것을 의미하고 말이다.


이러한 Critical Section에 들어가기 위한 entry Section 나가기 위한 exit Section이 추가적으로 있고, 이를 그림으로


critical section에 대한 이미지 검색결과


이와 같이 볼 수 있다.


자 이제 해결해야 할 문제는 어떻게 critical Section의 상호베타적 접근을 보장해주기 위한 해결책을 해.............보기 전에

Critical Section Problem에 대한 기준 3가지를 한 번 언급해보려 한다.


1. Mutual Exclusion

-> "상호 배제". 즉, 베타적인 접근을 보장해야 한다는 기준이다. critical section을 사용하는 가장 근본적인 이유라고 하겠다.

2. Progress

->"진행". Critical Section이 무기한 연기될 수 없다. 하나의 Critical Section이 다른 Critical Section에 의해 무기한 연기될 수 없다는 기준이다.

3. Bounded Waiting

-> "한계가 있는 기다림". 어떻게 보면 2와 동일한 말이다. 무기한 연기될 수 없으니깐 기다림에 있어서 제한을 둬야 한다는 기준이다.



이 3가지 기준을 모두 만족해야만 Critical Section Problem을 해결했다고 볼 수 있는 것이다.




그렇다면 구체적으로 들어가서 보자!

먼저 SW Solution을 분석해보자.


Peterson's Solution

위의 솔루션은 제한 조건이 있다.

1. 두 개의 Process에 대한 Solution

2. load, store instruction이 atomic하다. -> 요즘 시스템에는 맞지 않는 말이다.


그리고 2개의 variable을 사용한다.

1. int turn -> Critical Seciton에 누가 들어갈 것인지를 알려주는 변수

2. Boolean flag[2] -> Critical Section에 들어갈 것이라는 의사표시를 하는 변수


프로세스가 2개(Pi, Pj / i = 0, j = 1)가 있다고 했을 때 Peterson's Solution의 알고리즘은 아래와 같다.

entry_section에서 본인의 flag를 true로 바꾸고 turn값을 다른 process로 명명한다.

그리고 while문을 돌며 다른 process의 flag가 true이고, turn == 1일 경우 자신은 대기한다.


여기서 특이한 점은 P0에서 turn = 1을 수행하는 것인데.... 이는 turn에 대한 Consistency가 깨져도 Race Condition이 발생하지 않게 하기 위함이다.


해당 알고리즘은 두 개의 Process가 Critical Section에 접근하지 않으면 되는 것이다.

그렇다면 어떠한 경우에 while문을 빠져 나올 수 있는지를 확인해보자.


P0의 경우

flag[1]==false or turn == 0인 경우이고,

P1의 경우

flag[0] == faluse or turn == 1인 경우이다.


다른 process가 Critical Section에 들어갈 필요가 없다면(flag == FALSE), 내 process는 critical section에 들어가서 작업을 하면 되는 것이고,
flag가 모두 TRUE라면, turn에 의해서 가장 최근에 실행된 process와는 다른 thread가 critical section을 수행하게 된다.


다음으로는 HW Solution을 한 번 확인해보자.


HW Solution의 핵심은 검사와 값 변환을 한 번에 수행하는 것이다. sw라면 수행할 수 없지만 hw이기 때문에 두 개의 행동이 동시에 실행이 가능한 것.


lock이 False였다면? Lock을 가지고 있는 Process가 없다는 의미니깐, 내가 쓸게 하고 lock을 true로 변경해주고, 이전 값을 반환하게 되면, critical section으로 들어가 동작을 수행한다.

lock이 true면 누군가가 사용하고 있다는 의미니깐 계속 while문을 돌며 대기한다.


compare_and swap도 동일한 기능을 수행한다. 단지 compare과정(lock의 값이 내가 예상하는 값이 맞는지 확인)이 추가된 것일 뿐...


하지만 위의 방식처럼만 사용하게 되먼 Bounded Waiting이 보장되지 않는다.


그래서 아래와 같이 사용한다.



waiting[] 배열은 나 critical Section에 들어가고 싶어! 라고 하는 process들이 표시를 해놓는 공간이다.


Entry_Section

즉, a라는 process가 나 critical section 수행할거야! 라고 하면 waiting[a]를 true로 만들어주고, key값도 true로 만들어주고 기다린다.

key가 true이므로 while은 무조건 한 번 이상은 수행이 될 것이고,

test_and_set()에서 lock이 true라면(lock을 사용하고 있는 process가 있다면) key값은 계속 true를 유지할 것이고,

test_and_set()에서 lock이 false가 된다면 key 값은 false가 되어 critical section을 수행할 것이다.


End_Section

waiting배열을 circular하게 돌아가게 설정을 해놓는다. 즉, j는 i의 바로 옆 배열이라는 소리.

이 때 옆 배열이 나 자신이 아니고, waiting[j] = FALSE일 때는 j를 하나 더 증가시켜준다.(=다음 process는 critical section에 들어가지 않을거야 라는 의미)


그렇게 비교를 하다가 critical section에 들어갈 거야하는 process가 나올 경우 lock은 true를 유지한 채 waiting값만 false로 만들어 critical section으로 들어가게 한다.


만약 한바퀴를 돌아도 waiting이 true인 곳이 없다면 lock을 해제한다.


이게 어떻게 bounded waiting을 만족시키느냐??

index를 변경해가면서 waiting을 검사하므로 priority가 상대적으로 동작하게 된다. 따라서 bounded waiting을 자동적으로 만족하는 것!


















수능도 끝난 지금. 학생부 전형, 논술 전형 등등 다양한 수시 시즌을 보내고 있는 고3을 맞이하여 아주대학교에서도 면접을 보았다고 합니다.


고등학교 생활 3년 동안 C언어는 1도 몰랐었었는데 요즘 친구들은 C, C++, Python까지도 한 번 써보고, 아두이노 kit를 이용하여 간단하나마 뭐라도 만들어 보고 이를 면접에 활용한다는 소리를  듣고 와... 대단하다라는 생각을 하던 찰나 피보나치 정렬을 사용해보고, 피보나치 정렬이 버블 정렬보다 더 좋다는 대답에  교수님이 하신 질문...

"더 좋다의 기준은 무엇인가요???"

이 질문에 어떤 학생은... 빅오 표기법에 대해서 이야기를 했다는 것... ㅋ


진짜 빅오 표기법은 내가 자료구조 및 알고리즘 수업, 그것도 3학년에 되서야 처음 들어본 프로그램의 성능을 나타내는 지표 중 하나인 것을 알았는데 빅오 표기법을 면접 내용으로 꺼낼 수 있는 것 자체만으로도 정말 요즘 고3은 내가 보냈던 고3 생활보다 더 열심히 살아가고 있는구나라는 생각이 들었다.


교수님이 하시는 말씀을 들어보니 "모른다"라는 대답에 대해서는 점수를 깎지 않고, 거짓으로 대답하는 질문에 대해서만 점수를 깎았다고 하시는 것... 이러한 면접의 특성은 내가 회사에 들어갈 때도 동일하게 작용하지 않을까 하는 생각이 든다.



여담은 이쯤 하고

오늘 이렇게 수업 필기를 하는 이유는


교수님의 박사 생활 때 있었던 IBM에서의 인턴 생활을 하기까지, 졸업이 늦춰짐에도 불구하고 데이터 마이닝이라는 분야를 결정하여, 그렇게 돌진하신 일화가 너무 인상깊었기 때문이다.


데이터 마이닝이란?

대규모로 저장된 데이터 안에서 체계적이고 자동적으로 통계적 규칙이나 패턴을 찾아 내는 것이다. 다른 말로는 KDD(데이터베이스 속의 지식 발견, knowledge-discovery in databases)

이라고 위키 피디아에는 정의되어 있다.


유의미한 정보의 발견. 그리고 그 정보의 지식화.


예를 하나 들어보자.

어떠한 통계를 보니 월마트에서 금요일 퇴근 시간에 맥주와 기저귀와의 판매량이 다른 시간대보다 월등히 높다는 결과가 나왔다.

맥주와 기저귀... 이 둘은 전혀 상관관계가 없어 보이는 상품 묶음인데 왜 이러한 결과가 나왔는지 해당 제품들을  구매하는 사람들에게 물어본 결과

"금요일 저녁에 축구 리그전이 있는데 기저귀같이 부피가 큰 제품은 미리 사가지 않으면 축구 경기를 보다가 사가야 하는 경우가 생깁니다. 이를 미연에 방지하기 위해 맥주와 기저귀를 같이 사가는 것이죠"

이를 깨달은 마케팅 부서는 맥주 코너 옆에 기저귀 코너를 놓고 맥주 상품에는 기저귀 할인 쿠폰을, 기저귀에는 맥주 할인 쿠폰을 부착하였더니 매출이 더욱 올랐다는 일화가 있다.


데이터 마이닝은 맥주와 기저귀의 상관관계를 판매량이라는 데이터를 이용하여 정보화 하는 것이라고 보면 되는 것이다.


이러한 데이터 마이닝은 사용 가능한 분야가 정말 무궁무진하다.

알파고와 이세돌의 격전을 예로 한 번 들어보자.

알파고는 학습을 통해 바둑이라는 경기에 대한 패턴을 익힌다.

그리고 대국 진행 과정에서 이전에 놓인 대국의 패턴을 분석하여 미래를 예측하는(predictioin) AI인 것이다.

15수를 앞서 볼 수 있는 것(15개의 패턴이 연결되어 있는 것)과 20수를 앞서 볼 수 있는 것 중 20수를 앞서 볼 수 있는 머신이 더욱 좋은 성능을 가지게 될 것이다.


이를 통해 알 수 있는 것.

데이터 마이닝, 머신 러닝은 결과적으로 데이터의 패턴을 파악하는 것. 해당 패턴의 depth가 낮으면 가까운 미래만 예측 할 수 있을 것이고, 패턴의 depth가 깊으면 더욱 먼 미래까지 예측할 수 있을 것이다.


월마트의 예시도 일정 깊의 패턴을 해석하여 맥주와 기저귀와의 관계를 유의미하게 만든 것 중 하나라고 볼 수 있다.


이러한 prediction은  의료 분야에서도 사용될 수 있다.

"Body Parts on a chip"

우리의 몸은 다양한 기관이 유기적으로 연결되어 있다. 우리의 몸은 외부의 다양한 자극에 좌우되지 않기 위해 호르몬 등을 이용한 항상성 유지에 많은 에너지를 사용한다. 이러한 항상성 유지 메커니즘에 문제가 발생하면 우리의 몸 여기 저기에 문제가 발생하게 된다.

그러나 만약 신체 기관들 사이의 관계를 모두 파악하게 된다면, 우리 신체의 ph가 조금 낮아지게 되면 우리의 몸이 어떠한 변화를 야기하는지 모든 결과를 알 수 있다면? 병을 진단하는데 있어서 확실한 지표가 될 수 있을 것이다.

더 나아가서, 의사가 필요없을지도 모르겠다.

이러한 데이터들의 관계 역시 데이터 마이닝이라는 기법을 통해서 얻을 수 있는 information 중 하나인 것이다.

관계의 깊이가 더욱 깊어질 수록 accuracy가 더 올라가는..ㅎ


데이터 마이닝의 의미는 이쯤하고....

data와 information 그리고, knowledge에 대해서 한 번 이야기를 해보자.


data는 무엇일까? 데이터를 한국 말로 하면 "자료"라고 볼 수 있다. 자료는 있는 그대로 사용할 수 없다. 일련의 "해석" 과정을 거쳐 가치가 있는 것으로 변화시켜야 우리에게 쓸모가 있는 것이다.

음식으로 보면 재료라고 보면 되겠다.


이러한 데이터들을 유의미한 결과로 바꾼 결과가 바로 information(정보)이다. 맛있게 완성된 요리라고 할 수 있겠다.

그리고 이러한 정보를 쌓게 되면 바로 knowledge(지식)이 되는 것이다. 바로 언제든지 사용할 수 있는 레시피가 되는 것이다.


자 아래의 그림을 한 번 보자


데이터가 지식이 되는 과정은 정말 고되다. 변환된 데이터를 패턴화 시켜주는 데이터 마이닝 과정을 거치기 이전에만 3단계를 더 거쳐야 한다.


해당 과정은 아직까지는 노가다 말고는 해결 방법이 없다. 이 방법, 저 방법 다 써봄으로써 불필요한 데이터를 제거하고, 남아있는 데이터를 패턴화 시키기 위해 끊임없는 시행착오를 거쳐야 한다.

어떻게 보면 데이터 마이닝의 어두운 면이랄까....ㅋ



데이터 마이닝에 관해 들은 것은 많지만 직접 해보지는 않았다. 지금은 이전과 다르게 다양한 알고리즘들이 나와 있을 것이고, 하나하나 공부해 가면 정말 무궁무진한 학문임은 틀림없다.


빅데이터, IoT, 4차 산업 혁명. 이러한 산업의 변화가 어떠한 결과를 야기시킬지 정말 궁금하고 기대된다.









+ Recent posts