'NodeJS'에 해당되는 글 5건
- 2013.01.19 OctoberSkyJs 1차 스터디 후기 4
- 2012.11.20 [Node.js] For문과 비동기 Callback
- 2012.11.20 Node.js or Javascript Global Scope Test
- 2012.11.19 Node.js 비동기 이벤트 실행
- 2012.11.18 Node.js 실행스택(Execution Stack) 이벤트 처리 과정
OctoberSkyJs 1차 스터디 후기
OctoberSkyJs 1차 스터디 후기
올해 들어 나름 야심 차게 시작하고 전부터 큰 관심만 가졌던 Node.JS 스터디 모임인 "OctoberSkyJs 1차 스터디 후기"를 간단히 제 블로그를 통해 남겨봅니다.
오늘은 개인적인 사정으로 인해 당일 발표 중 첫 번째, 두 번째 발표인 "Buffer"와 "C/C++ Addons"는 아쉽게도 들을 수 없었지만(특히 C/C++ Addons는 꼭 듣고 싶었던 발표이기에 더 큰 아쉬움이 남습니다.;;),
차후 "Groups Mail"을 통해 공개될 "발표 자료"를 기대해 봅니다. plz
그럼 후기의 본론인 스터디 얘기를 하자면, 오늘 제가 들은 발표는 총 2개의 발표였으며, 그 중 세 번째 주제였던 @백정상님의 "Cluster"와 당일 발표자분의 부재로 인해 그 자리를 대신 메꿔 주셨던(소위 땜빵 발표?) @채수원님의 "libuv"에 대한 얘기였습니다.
특히 세 번째 발표인 "Cluster"란 주제는 스터디 예습을 전혀 하지 못한 제겐 시작부터 큰 "멘붕"을 느끼게 했고, 기반 지식(OS, 하드웨어, 엔진(V8)) 또한 그리 깊지 않아 발표 내내 최대한 이해하기 위해 노력했던 시간이었던 거 같습니다.(다행히도 다른 분들의 여러 질문이 이해하는 데 도움이 많이 되었답니다.ㅋㅋ)
스터디 내용 중 생각나는 내용에 대한 주제를 간단히 적어보자면 Cluster란?, 적용 시 성능 향상은?(약 20 ~ 40%?), Child-Process 와의 관계? 등의 이야기였고 물론 100% 이해하기 힘들고 제겐 어려운 내용이었지만 성능 향상에 대한 새로운 부분을 알게 되어 아주 유익한 시간이었습니다.
또한 "땜방 발표"를 해주셨던 @채수원님의 "Libuv" 또한 Clouster의 내용과 같이 기반 지식이 부족한 현재로선 100% 이해하기 힘든 내용이었지만 역시 의미 있는 시간이었습니다.
그리고 발표하셨던 내용 중 어느 "한 부분"이 제겐 인상 깊게 남아 아랫글로 옮겨 봅니다.
"Node.JS는 JVM과는 달리 OS와 Machine 간에 최적화 레이어가 존재하지 않는다.(뒤에 따라오는 말은 그에 대한 성능과 관련된 말씀이셨는데 정확히 생각나지 않고 이해 또한 잘 되지 않아 이 글에 옮겨 적지 않겠습니다.(괜찮으시다면 댓글로 직접 남겨 주셔도 좋을 듯합니다.^^;;))
그럼 후기의 끝으로 앞으로 남은 "스터디" 현재 모든 맴버들과 같이 잘 마무리 할 수 있기를 빌며...
1차 후기를 마칩니다.!!
[Node.js] For문과 비동기 Callback
"JS 비동기 이벤트 실행 순서"로 인해 첫 번째 예제의 타이머 이벤트 callback은 for 문이 종료된 후 실행된다.
즉, 이벤트 큐에 쌓인(Event Loop 감지 후) 이벤트 callback들의 실행 시점은 for문 에서 선언된 i 변수가 증감 후 9가 되어 루프를 빠져나온 시점인 것이다.
1. Client-Side 코드 예제
for (var i = 0; i < 10; i++){
this.setTimeout(function(){
console.log(i); // 10
}, 10);
}
// 아래 나머지 예제들은 문법 상 차이만 존재하며, 의미는 동일하다.
// 즉, 타이머 이벤트나 전달되는 callback에 즉시 실행 함수를 랩핑하여 클로저를 발생시켜 위 문제를 해결한다.
for (var i = 0; i < 10; i++){
// 타이머 이벤트에 즉시 실행 함수를 랩핑.
(function(i){
this.setTimeout(function(){
console.log(i); // 0 ~ 9
}, 10);
})(i);
}
for (var i = 0; i < 10; i++){
// 전달되는 타이머 이벤트의 callback에 즉시 실행 함수를 랩핑.
this.setTimeout((function(i){
return function(){
console.log(i); // 0 ~ 9
}
})(i), 10);
}
2. Server-Side Node.js 코드 예제
- Server-Side Javascript인 Node.js도 위 동작 방식과 동일하다.
for (var i = 0; i < 10; i++){
// setTimeout 타이머와 같이 비동기로 동작한다
process.nextTick(function(){
console.log(i); // 10
});
}
for (var i = 0; i < 10; i++){
// 타이머 이벤트에 즉시 실행 함수를 랩핑.
(function(i){
process.nextTick(function(){
console.log(i); // 0 ~ 9
});
})(i);
}
for (var i = 0; i < 10; i++){
global.setTimeout((function(i){
return function(){
console.log(i); // 0 ~ 9
}
})(i), 10);
}
3.결과
Node.js or Javascript Global Scope Test
1. Client-Side Javascript 전역 객체
// 명시적 전역 변수 선언
var global1 = 'global1';
(function(){
// 암묵적 변수 선언(안티패턴)
global2 = 'global2';
this.global3 = 'global3';
})();
console.log(typeof window.window.global1); // string
console.log(typeof window.window.global2); // string
console.log(typeof window.window.global3); // string
// delete 연산자로 window 객체의 property 삭제
delete window.window.global1;
delete window.window.global2;
delete window.window.global3;
console.log('');
// 명시적으로 선언된 global1 전역 변수는 엄밀히 말해 아래 결과와 같이 delete 연산자로 객체가 소멸되지 않는다.
// 즉, 객체 속성 및 배열의 요소를 제거하는 delete 연산자로 삭제가 되지 않기 때문에 엄밀히 말해 window 객체의 속성으로 볼 수 없다.
console.log(typeof window.window.global1); // string
console.log(typeof window.window.global2); // undefined
console.log(typeof window.window.global3); // undefined
자바스크립트 변수
자바스크립트 함수 유효범위(Scope)란?
2. Server Side Javascript Node.js 전역 객체
2.1 확장 모듈 helloworldExFn.js 코드
module.exports.helloworldExFn = (function(){
var helloworldEx = function(){
this.id = 'mohwa';
this.name = 'mohwaName';
return this;
}
// 전역 속성 선언 및 할당
global.g_createValue1 = 'g_createValue1';
this['g_createValue2'] = 'g_createValue2';
return helloworldEx;
})();
2.2 호출 페이지 코드
// Node 전역 객체의 Console.log 함수 반환
console.log('1. ' + global.console.log);
// Node 전역 객체의 생성자 함수 반환
console.log('2. ' + global.constructor);
// 빈 전역 객체 반환
console.log('3. ' + this);
// Node.js에서는 Client-Side JS와 달리 함수 밖 "this"는 전역 객체인 global을 가리키지 않는다.
// 빈 전역 객체 생성자 함수 반환
console.log('4. ' + this.constructor);
(function(){
// Node 전역 객체의 Console.log 함수 반환(Client-Side JS와 같이 함수 객체 내부에서는 빈 전역 객체가 아닌 Node 전역 객체 "global"을 반환한다.)
console.log('5. ' + this.console.log);
})();
// 확장 모듈 내부에 전역 변수 생성.
// require(객체) 메서드는 외부 리소스로 제공된 확장 모듈을 가져와 반환({} 타입)한다.
// 그리고 제공된 확장 모듈안 helloworldExFn 맴버는 반환되는 객체의 맴버로 정의된다.
var obj = new require('./helloworldEx.js').helloworldExFn();
// new helloworldExFn() 객체의 id 속성 반환
console.log('6. ' + obj.id);
// new helloworldExFn() 객체의 name 속성 반환
console.log('7. ' + obj.name);
var g_createValue1 = 'g_createValue1';
// 명시적 전역 변수는 g_createValue1를 제거한다.
// 하지만 Client-Side JS와 동일하게 명시적 전역변수는 delete 연산자를 통해 제거되지 않는다.
delete g_createValue1;
// 확장 모듈 내부에서 선언된 암묵적 전역 변수인 g_createValue2를 제거한다.
delete g_createValue2;
// 확장 모듈 내부에서 선언된 암묵적 전역 변수인 g_createValue3를 제거한다.
delete g_createValue3;
console.log('8. ' + typeof g_createValue1);
console.log('9. ' + typeof g_createValue2);
console.log('10. ' + typeof global['g_createValue3']);
3. 결과:
이전 포스트에서 "Node.js 아키텍처 방식"에 대해 간단히 설명한 적이 있다.
즉, "Node 아키텍처 최 상단 레이어"인 "Node Standard LIbrary"를 통해 기존 Client-Side Javascript 문법이 활용 가능하며, 전체 적인 동작 방식(전역객체, 유효범위 등..)또한, 기존 JS와 많은 부분 흡사하다는 것을 알 수 있다.
Node.js 비동기 이벤트 실행
1. Node.js 비동기 실행 테스트
(function(){
var args = arguments;
// 첫 번째 비동기 요청
this.setTimeout(function(){
console.log('1 Async Start=' + new Date().getTime());
// 첫 번째 동기 CallBack(다음 비동기 요청을 지연(대기)시킨다.)
for (var i = 0; i < 10; i++){
console.log('1 Async Time=' + new Date().getTime());
}
}, 1001);
// 두 번째 비동기 요청
this.setTimeout(function(){
console.log('2 Async Start=' + new Date().getTime());
// 두 번째 비동기 CallBack
setTimeout(function(){
for (var i = 0; i < 10; i++){
console.log('2 Async Time=' + new Date().getTime());
}
}, 10);
}, 1000);
// 세 번째 비동기 요청
this.setTimeout(function(){
console.log('3 Async Start=' + new Date().getTime());
// 세 번째 비동기 CallBack
setTimeout(function(){
for (var i = 0; i < 10; i++){
console.log('3 Async Time=' + new Date().getTime());
}
}, 10);
}, 1000);
})();
2. 결과
1. (두, 세)번째 비동기 요청이 "요청 실행 시점"(1초)에 맞게 먼저 실행된다.(1353241683913, 1353241683915)
2. 첫 번째 비동기 요청이 실행된다.(1353241683915)
3. 첫 번째 요청에 대한 동기 CallBack이 실행된다.(Javascript Code Block(1353241683916))
4. "비동기 이벤트 실행 순서"에 따라 첫 번째 CallBack의 "동기식 Javascript Code Block" 실행 완료 후 (두, 세)번째 CallBack이 동시 진행 됐다.(1353241683925)
5. (두, 세) 번째 CallBack이 동시 실행 후 완료된다.(1353241683925)
Node.js 비동기 처리의 환상
http://seorenn.blogspot.kr/2011/05/nodejs_26.html
Javascript Single Thread
http://mohwaproject.tistory.com/entry/javascript-single-thead
Node.js 실행스택(Execution Stack) 이벤트 처리 과정
1. Node.js 아키텍처 및 프로세스 모델
1. Node.js는 크게 Javascript 언어 레이어와 (C, C++) 언어 레이어로 나뉜다.
2. C++로 작성된 구글의 Javascript 엔진인 "V8"과 이벤트 기반 Non-Blocking I/O(비동기 I/O)를 관리하는 "libero(Thread Poll 담당)"와 이벤트 루프를 담당하는 "libev"가 아키텍처 최하단에 위치한다.
3. 그 위에 Socket 및 Http등에 대한 "node bindings" 레이어(노드에서 작성된 API(C++))는 "Node Standard Library"의 인터페이스 역활을 한다.(Node 저장소에 있는 소스 중 src/*.cc 에 포함되어 있고 Node Standard Library 대부분이 래퍼들과 동작하게 된다.)
4. Node Standard Library 레이어는 Node Bindings 레이어에서 제공되는 Node API(C++)를 시스템상에서 Javascript 문법을 이용해 I/O 프로그래밍을 할 수 있도록 지원하는 Server Side 라이브러리이다.
var server = require('http');
var fs = require('fs');
var url = require('url');
var reqUrl = '';
server.createServer(function(req, res){
fs.readFile('./nodeHtml.html', encoding='utf-8', function(err, data){
if (err){
throw err;
}
else{
res.write(data);
res.end();
}
});
}).listen(3000);
3. 실행 스택(Execution Stack) 이벤트 처리 과정
1. 노드는 Single Thread를 사용하므로, 실행 스택(Execution Stack)도 하나만 존재한다.(Stack을 통해 Event Loop가 처리된다.)
2. 한번에 하나의 이벤트(Node API에 포함된 각 이벤트)와 관련된 Stack만 추가된다.
즉, Event Loop를 통한 서로 간의 간섭(Dead Lock(리소스 병목현상))은 일어나지 않는다.(한번에 하나의 이벤트만 추가되기 때문에..)
"실행 스택 " 최하단 에는 Event Loop를 처리하는 ev_loop()가 존재하며, 계속 실행되고 있다가 이벤트 발생하면 감지 후 필요한 Stack을 실행 스택에 추가시킨다.
3.1 "실행스택" 이 추가되는 이벤트를 처리하는 과정
1. 첫 번째 사용자가 웹 서버(Node.js로 구현된..)에 index.html을 요청한다.
2. 이벤트 루프(Event Loop)는 이를 감지 후 요청 소켓을 읽기 위해 "scket_readble Stack"을 추가한다.(현재 Stack: 1개)
3. HTTP 요청을 해석하는 "http_parse Stack"을 추가 하고(현재 Stack: 2개) index.html 파일에 대한 요청이므로 "load('index.html') Stack"을 추가하고(현재 Stack: 3개) index.html 파일 읽기를 요청한다.
4. index.html을 읽어 들이는 I/O를 요청했으므로 그로 인해 추가된 Stack 3개(scket_readble Stack, http_parse Stack, load('index.html') Stack)를 추가한 순서대로 제거해 나간다.(모두 제거되면 실행스택은 이벤트 루프만 돌고 있는 대기 상태에 있게 된다.)
*** 아직까지는 첫 번째 사용자가 요청한 index.html의 응답을 보내기 위해 파일 I/O를 요청만 완료된 상태이며, 응답을 기다리는 중이다.!!!! ***
5. 이 상태(상황)에서 메모리상에 존재하는 두번째 사용자의 index.html 요청이 들어온다.
6. 두 번째 요청 또한, 첫 사용자와 동일한 과정을 거쳐 실행 스택에 해당 Stack(각 이벤트에 대한 Stack 3개)들을 추가 시켜 나간다.
7. "두 번쨰 요청을 처리하는 중!!" 첫 번째 사용자 요청인 index.html 파일을 읽는 I/O 처리가 완료되었다.!!!!
"해당 이벤트가 발생했지만 현재 두 번째 "요청에 대한 Stack이 존재"하므로 바로 처리되지 않고 이벤트를 대기 시킨다.
설명:
Non-Blocking I/O 방식은 요청 이벤트를 blocking 하지 않는다.
즉, 두 번째 요청에 대한 Stack이 모두 제거(추가된 순서대로...)돼야 이벤트 루프는 다음 이벤트를 처리해 나간다.
8. 대기 중이던 첫 번째 사용자 요청에 대한 응답(로드된 index.html 파일 읽기 이벤트)을 처리하기 위해 "file_loaded() Stack"을 추가(현재 Stack: 1개)해 I/O가 돌려준 index.html 파일을 받는다.
9. 첫 번째 요청에 응답하기 위해 "http_respond Stack"을 추가 후(현재 Stack: 2) 사용자에게 받은 index.html 파일로 응답을 생성해 사용자에게 응답을 보낸다.
10. 응답이 완료됐으며, 그에 따라 첫 번째 사용자의 응답을 위해 추가된 모든 Stack은 모두 순차적(추가된 순서)으로 제거된다.
11. 두 번째 사용자 또한 이 과정을 통해 해당 사용자 응답을 보낸 후 스택에서 제거된다.
단 비동기 방식(이벤트 방식)은 응답에 대한 순서를 보장하지 않는다.
즉, 요청은 순차적으로 이루어지나, 그에 대한 응답은 순서를 보장하지 않는다는 뜻이다.
C++ Addon With Node.js
Node.js Ebay
http://www.slideshare.net/rheehot/nodejs-review
Node JS 프로그래밍(책)
http://www.yes24.com/24/goods/6271069