병렬성
초기의 컴퓨터는 하나의 CPU만을 가지고 있었다. 그렇기 때문에 두 가지 일을 동시에 처리하는 대신, 동시에 처리하는 '척'을 했다. 예를 들면 주황-초록-보라 순서대로 아주 조금씩 작업을 하는 것이다. 사람이 캐치하기 어려울 만큼 작은 단위로 일을 쪼개서 하면, 사람은 마치 동시에 일을 하는 것처럼 느낄 수 있는 것이다.
하지만 멀티 프로세서가 일반화되면서, '진짜로' 동시에 일을 처리해야하는 상황에 처하게 되었다. 동시에 일을 처리한다면, 같은 자원에 동시에 접근하는 경우도 발생할 수 밖에 없다.
0x0001이라는 메모리에 100이라는 값이 저장되어 있고, 10을 빼서 저장하는 프로세스1과 20을 빼서 저장하는 프로세스2가 이 메모리에 동시에 접근하는 경우를 생각해보자. 두 프로세스가 실행된 후 기대하는 결과는 다음과 같을 것이다.
프로세스1 | 프로세스2 | 0x0001 |
100 | ||
0x0001 읽음 | 100 | |
읽은 값에서 10을 뺌 (100 - 10) | 100 | |
0x0001에 저장 | 90 | |
0x0001 읽음 | 90 | |
읽은 값에서 20을 뺌 (90 - 20) | 90 | |
0x0001에 저장 | 70 |
하지만 이런 결과가 생길 수도 있다.
프로세스1 | 프로세스2 | 0x0001 |
100 | ||
0x0001 읽음 | 100 | |
읽은 값에서 10을 뺌 (100 - 10) | 100 | |
0x0001 읽음 | 100 | |
읽은 값에서 20을 뺌 (100 - 20) | 100 | |
0x0001에 저장 | 90 | |
0x0001에 저장 | 80 |
0x0001와 같은 자원을 공유자원이라고 하는데, 이와 같은 상황에 대한 적절한 처리가 없으면 기대한 결과값이 나오지 않을 수 있다. 이 문제를 해결하기위해, 프로세스의 흐름을 하나의 트랜잭션(실행 흐름의 단위)로 묶어서 한꺼번에 처리하도록 만들 수 있다. 그리고 그동안은 다른 프로세스가 자원에 접근하지 못하도록 락을 걸어둔다.
하나의 트랜잭션 |
0x0001 읽음 |
읽은 값에서 n을 뺌 (100 - n) |
0x0001에 저장 |
이같은 해결 방법에도 문제점은 존재한다. 락이 풀릴 때까지 다른 프로세스가 대기해야하기때문에 멀티태스킹의 목적과는 멀어질 수 있다. 공유자원에 락이 풀릴때까지 반복적으로 시도하며 락이 풀렸는지 체크하거나, 대기열에서 기다리다가 순서가 되면 들어가는 것 정도의 방법적인 차이는 있지만 대기가 발생한다는 것은 어쩔 수 없다.
또는 교착상태에 빠질 수 있다. 프로세스1은 자원 2를 가지고 있는데, 자원 1을 기다리고 있다. 프로세스2는 자원 1을 가지고 있는데, 자원 2를 기다리고 있다. 서로가 가진 자원을 내놓기를 기다리면서 무한정 대기해야하는 상황에 빠지는 것이다.
* 교착상태는 아래의 네 가지 조건을 동시에 만족하는 경우에 발생한다. 즉, 교착 상태를 해결하기 위해서는 네 가지 중 한 가지 이상의 요인을 해결해야 한다.
1) 상호배제 : 공유자원을 어느 한 프로세스가 독점적으로 사용함
2) 점유 대기 : 자원을 점유한 상태에서 다른 자원을 요청함
3) 비선점 : 자원을 강제로 빼앗을 수 없음
4) 순환 대기 : 서로 순환적으로 다른 프로세스가 갖고 있는 자원을 요구함.
비동기성
멀티태스킹의 병렬성 문제를 해결하기 위해, 비동기적인 통신을 이용하는 것은 좋은 아이디어가 될 수 있다. 요청한 응답이 도착할 때까지 대기하는 것이 아니라, 도착할 동안에도 멈추지 않고 동작하는 것이 비동기성이고, 이와 같은 웹브라우저의 통신 스타일을 AJAX라고 한다.
책에서는 jQuery로 예시를 들었지만, 본 글에서는 자바스크립트 예시코드를 작성하였습니다.
자바 스크립트에서는 AJAX를 구현하기 위해 XMLHttpRequest 객체를 활용한다.
const DONE = 4
const OK = 200
// XMLHttpRequest 객체 생성
var xhr = new XMLHttpRequest();
// 콜백 함수 설정 => xhr의 readyState 상태가 변할때마다 함수가 호출됨
xhr.onreadystatechange = function () {
if (xhr.readyState === DONE && xhr.status == 200) {
console.log("모든 데이터가 전송 완료 되었습니다.")
console.log("서버데이터 요청 결과는 성공입니다..")
}
}
// 비동기화 요청 - 요청 방식, 호출 페이지 등록
xhr.open("GET", "http://www.example.com")
// 요청 전송
xhr.send()
XMLHttpRequest 객체를 사용하게 되면 콜백이 중첩된 스파게티 코드가 만들어지기 쉽기 때문에 조금 더 현대적인 방법으로, Promise-Style을 활용하기도 한다.
간단한 Promise의 예시 코드는 아래와 같다.
// resolve : 이행되었을때의 콜백함수 , reject : 거부된 경우의 콜백 함수
const myPromise = new Promise((resolve, reject) => {
resolve('성공했습니다.') // then 부분 실행
}
myPromise
.then((data) => { console.log(data) })
Promise를 활용하면, fetch API를 통해 비동기 요청을 보낼 수 있다.
// Http 응답을 나타내는 Response 객체를 래핑한 Promise 객체를 반환
fetch("http://www.example/com")
.then((response) => console.log(response.text())) // 성공시 실행
.catch(console.log("실패하였습니다.") // 실패시 실행
-- 확인 문제--
1. 멀티태스킹을 위해 비동기적인 통신방법인 AJAX를 활용할 수 있다. AJAX를 구현하기위한 코드의 빈칸에 들어갈 말은?
const DONE = 4
const OK = 200
// 비동기 통신을 위한 객체 생성
var xhr = new _______(A)_________();
// 콜백 함수 설정 => xhr의 readyState 상태가 변할때마다 함수가 호출됨
xhr._________(B)_________ = function () {
if (xhr.readyState === DONE && xhr.status == 200) {
console.log("모든 데이터가 전송 완료 되었습니다.")
console.log("서버데이터 요청 결과는 성공입니다..")
}
}
// 비동기화 요청 - 요청 방식, 호출 페이지 등록
xhr.___(C)__("GET", "http://www.example.com")
// 요청 전송
xhr._____(D)_____()
2. 병렬성의 문제에서, 공유자원이 교착 상태가 발생하는 원인은 무엇인가 ?
1) _____ : 공유자원을 어느 한 프로세스가 독점적으로 사용함
2) _____ : 자원을 점유한 상태에서 다른 자원을 요청함
3) _____ : 자원을 강제로 빼앗을 수 없음
4) _____ : 서로 순환적으로 다른 프로세스가 갖고 있는 자원을 요구함.
-- 정답 --
1. (A) XMLHttpRequest
(B) onreadystatechange
(C) open
(D) send
2. 1) 상호배제
2) 점유대기
3) 비선점
4) 순환 대기
'CS > BOOK' 카테고리의 다른 글
[한 권으로 읽는 컴퓨터 구조와 프로그래밍] 14. 인공지능 (1) | 2024.05.08 |
---|---|
[한 권으로 읽는 컴퓨터 구조와 프로그래밍] 13. 컴퓨터 보안 (1) | 2024.05.01 |
[한 권으로 읽는 컴퓨터 구조와 프로그래밍] 11. 알고리즘 아이디어 (0) | 2024.04.24 |
[한 권으로 읽는 컴퓨터 구조와 프로그래밍] 10. 웹 브라우저를 활용한 프로그래밍 (0) | 2024.04.23 |
[한 권으로 읽는 컴퓨터 구조와 프로그래밍] 9. 웹브라우저 (0) | 2024.04.17 |