기존 프로그래밍 모듈에서 I/O 작업은 일반적인 로컬 기능 호출과 같습니다. 기능이 실행되기 전에 프로그램이 차단되어 계속 실행할 수 없습니다. 차단 된 I/O는 각 프로세스가 독립적 인 사람과 같으며 모든 사람을 구별 할 목적으로, 모든 사람을 동시에 동시에 수행 할 수 있으며 다음에 무엇을 해야하는지 결정하기 전에 이전의 일을 기다려야합니다. 그러나 컴퓨터 네트워크와 인터넷에서 널리 사용되는 "하나의 사용자, 하나의 프로세스"모델은 매우 확장 가능합니다. 여러 프로세스를 관리 할 때 많은 메모리가 소비되며 컨텍스트 전환도 많은 리소스를 차지할 것입니다. 이는 운영 체제에 큰 부담이되며 프로세스 수가 증가함에 따라 시스템 성능이 급격히 부패합니다.
멀티 스레딩은 대안입니다. 스레드는 동일한 프로세스에서 다른 스레드와 메모리를 공유하는 가벼운 프로세스입니다. 기존 모델의 확장과 비슷하며 여러 스레드를 동시에 실행하는 데 사용됩니다. 하나의 스레드가 I/O 작업을 기다리는 경우 다른 스레드가 CPU를 인수 할 수 있습니다. I/O 작업이 완료되면 앞에서 대기 대기 스레드가 깨어납니다. 즉, 실행중인 스레드를 중단 한 다음 나중에 재개 할 수 있습니다. 또한, 스레드는 일부 시스템에서 다른 코어 CPU의 다른 코어 아래에서 병렬로 실행될 수 있습니다.
프로그래머는 스레드가 몇시에 실행되는지 모릅니다. 공유 메모리에 대한 동시 액세스를 처리해야하므로 일부 동기화 프리미티브를 사용하여 잠금 또는 세마포어를 사용하는 것과 같은 특정 데이터 구조에 대한 액세스를 동기화하여 스레드가 특정 동작 및 계획에서 실행되도록해야합니다. 스레드 사이의 공유 상태에 크게 의존하는 응용 프로그램은 강한 무작위성과 찾기 어려움으로 쉽게 이상한 문제를 가질 수 있습니다.
또 다른 방법은 CPU를 명시 적으로 공개하고 다른 스레드에 CPU 시간을 넘겨주는 다중 스레드 협업을 사용하는 것입니다. 스레드의 실행 계획을 개인적으로 제어하기 때문에 동기화의 필요성이 줄어들지 만 프로그램의 복잡성과 오류 가능성도 증가하며 멀티 스레딩 문제를 피하지 않습니다.
이벤트 중심 프로그래밍이란 무엇입니까?
이벤트 중심 프로그래밍은 이벤트가 프로그램의 실행 프로세스를 결정하는 프로그래밍 스타일입니다. 이벤트는 이벤트 핸들러 또는 이벤트 콜백으로 처리됩니다. 이벤트 콜백은 데이터베이스가 쿼리 결과를 반환하거나 사용자가 버튼을 클릭하는 것과 같은 특정 이벤트가 발생할 때 호출되는 기능입니다.
기존 차단 된 I/O 프로그래밍 모드에서 데이터베이스 쿼리는 다음과 같습니다.
코드 사본은 다음과 같습니다.
result = query ( 'select * where id = 1');
do_something_with (결과);
위의 쿼리 기능은 기본 데이터베이스가 쿼리 작업을 완료하고 반환 할 때까지 현재 스레드 또는 프로세스를 대기 상태로 유지합니다.
이벤트 중심 모델 에서이 쿼리는 다음과 같습니다.
코드 사본은 다음과 같습니다.
query_finished = function (결과) {
do_something_with (결과);
}
query ( 'select * where id = 1', query_finished);
먼저 쿼리가 완료된 후 수행 할 작업이 포함 된 query_finished라는 함수를 정의합니다. 그런 다음이 기능을 매개 변수로 쿼리 함수로 전달하십시오. 쿼리 실행 후 쿼리 결과를 반환하는 대신 query_finished가 호출됩니다.
관심있는 이벤트가 발생하면 결과 값을 단순히 반환하는 대신 정의하는 기능이 호출됩니다. 이 프로그래밍 모델을 이벤트 중심 프로그래밍 또는 비동기 프로그래밍이라고합니다. 이것은 노드의 가장 명백한 기능 중 하나입니다. 이 프로그래밍 모델은 I/O 작업을 실행할 때 현재 프로세스가 차단되지 않음을 의미합니다. 따라서 여러 I/O 작업을 병렬로 실행할 수 있으며 작업이 완료된 후에 해당 콜백 기능이 호출됩니다.
이벤트 중심 프로그래밍의 기본 레이어는 이벤트 루프에 의존합니다. 이벤트 루프는 기본적으로 이벤트 감지 및 이벤트 프로세서 가이 두 기능의 연속 루프 호출을 트리거하는 구조입니다. 각 루프에서 이벤트 루프 메커니즘은 발생한 이벤트를 감지해야합니다. 이벤트가 발생하면 해당 콜백 함수를 찾아 호출합니다.
이벤트 루프는 프로세스에서 실행되는 스레드 일뿐입니다. 이벤트가 발생하면 이벤트 프로세서는 단독으로 실행될 수 있으며 중단되지 않습니다. 즉.
1. 최대 한 이벤트 콜백 함수가 특정 순간에 실행 중입니다.
2. 실행할 때 이벤트 프로세서가 중단되지 않습니다
이를 통해 개발자는 더 이상 스레드 동기화 및 공유 메모리의 동시 수정에 대한 두통을 가질 수 없습니다.
잘 알려진 비밀 :
오래 전부터 시스템 프로그래밍 커뮤니티의 사람들은 이벤트 중심 프로그래밍이 많은 컨텍스트를 절약 할 필요가 없었기 때문에 높은 동시성 서비스를 만드는 가장 좋은 방법이라는 것을 알고 있었기 때문에 많은 컨텍스트 스위치가 아니라 많은 메모리를 저장하고 많은 실행 시간을 절약했습니다.
천천히이 개념은 다른 플랫폼과 커뮤니티에 스며 들었고 Ruby의 이벤트 머신, Perl 's AnyEvnet 및 Python's Twisted와 같은 일부 유명한 이벤트 루프 구현이 등장했습니다. 이 외에도 다른 많은 구현과 언어가 있습니다.
이러한 프레임 워크를 개발하려면 프레임 워크 및 프레임 워크 별 클래스 라이브러리와 관련된 특정 지식을 배워야합니다. 예를 들어, 이벤트 머신을 사용하는 경우 비 블로킹의 이점을 누리려면 동기 클래스 라이브러를 사용하지 않아야하며 이벤트 머신의 비동기 클래스 라이브러리 만 사용할 수 있습니다. 블로킹 라이브러리 (예 : 대부분의 Ruby의 표준 라이브러리)를 사용하는 경우 이벤트 루프가 계속 차단되어 I/O 이벤트 처리가 수시로 차단되므로 서버가 최적의 확장 성을 잃습니다.
노드는 원래 비 블로킹 I/O 서버 플랫폼으로 설계되었으므로 일반적으로 실행중인 모든 코드가 비 차단이 될 것으로 예상해야합니다. JavaScript는 매우 작고 I/O 모델을 강제하지 않기 때문에 (표준 I/O 클래스 라이브러리가 없기 때문에) Node는 매우 순수한 환경에 내장되어 있으며 레거시 문제가 없습니다.
노드 및 JavaScript가 비동기 응용 프로그램을 단순화하는 방법
Node의 저자 Ryan Dahl은 처음에 C를 사용 하여이 프로젝트를 개발했지만 기능 호출을 유지 관리하는 맥락이 너무 복잡하여 코드 복잡성이 높다는 것을 발견했습니다. 그런 다음 Lua로 전환했지만 Lua는 이미 몇 가지 차단 I/O 라이브러리를 가지고 있습니다. 차단 및 비 블로킹의 혼합은 개발자를 혼동하고 많은 사람들이 확장 가능한 응용 프로그램을 구축하지 못하게 할 수 있습니다. 따라서 Lua는 Dahl에 의해 버려졌습니다. 마지막으로 그는 JavaScript, JavaScript의 폐쇄 및 첫 번째 수준의 객체의 기능으로 바뀌 었으며, 이는 JavaScript가 이벤트 중심 프로그래밍에 매우 적합합니다. JavaScript의 마법은 노드가 인기있는 주된 이유 중 하나입니다.
폐쇄는 무엇입니까?
폐쇄는 특수 함수로 이해 될 수 있지만 정의 된 범위에서 변수를 상속하고 액세스 할 수 있습니다. 콜백 함수를 다른 함수로 매개 변수로 전달하면 나중에 호출됩니다. 마술은이 콜백 함수가 나중에 호출 될 때 실제로 자신을 정의하는 컨텍스트와 부모 컨텍스트의 변수를 기억하고 정상적으로 액세스 할 수 있다는 것입니다. 이 강력한 기능은 노드의 성공의 핵심입니다.
다음 예제는 웹 브라우저에서 JavaScript 클로저의 작동 방식을 보여줍니다. 버튼에서 독립형 이벤트를 듣고 싶다면 다음을 수행 할 수 있습니다.
코드 사본은 다음과 같습니다.
var clickcount = 0;
document.getElementById ( 'myButton'). onclick = function () {
clickcount += 1;
ALERT ( "클릭" + CLICKCOUNT + "TIMES.");
};
이것이 jQuery를 사용할 때 :
코드 사본은 다음과 같습니다.
var clickcount = 0;
$ ( '버튼#myButton'). 클릭 (function () {
ClickEdCount ++;
ALERT ( 'Clicked' + ClickCount + 'Times.');
});
JavaScript에서 함수는 첫 번째 유형의 객체입니다. 즉, 기능을 다른 함수로 매개 변수로 전달할 수 있습니다. 위의 두 가지 예에서, 전자는 함수를 다른 함수에 할당하고 후자는 함수를 다른 함수로 전달합니다. 클릭 이벤트 처리 함수 (콜백 함수)는 함수가 정의하는 코드 블록 아래의 각 변수에 액세스 할 수 있습니다. 이 예에서는 부모 폐쇄에 정의 된 클릭 카운트 변수에 액세스 할 수 있습니다.
클릭 카운트 변수는 글로벌 범위 (JavaScript의 가장 바깥 쪽 범위)에 있으며 사용자가 버튼을 클릭하는 횟수를 저장합니다. 다른 코드와 충돌하기 쉽기 때문에 변수를 글로벌 범위로 저장하는 것은 일반적으로 나쁜 습관입니다. 변수를 사용하는 지역 범위에 변수를 넣어야합니다. 대부분의 경우 코드를 하나의 기능으로 래핑하면 다른 폐쇄를 만드는 것과 같습니다. 이는 다음과 같이 글로벌 환경을 쉽게 오염시키는 것을 피할 수 있습니다.
코드 사본은 다음과 같습니다.
(기능() {
var clickcount = 0;
$ ( '버튼#myButton'). 클릭 (function () {
ClickCount ++;
ALERT ( 'Clicked' + ClickCount + 'Times.');
});
} ());
참고 : 위의 코드의 일곱 번째 줄은 함수를 정의하고 즉시 호출합니다. 이것은 JavaScript의 일반적인 디자인 패턴입니다. 함수를 만들어 새 범위를 만듭니다.
클로저가 비동기 프로그래밍에 도움이되는 방법
이벤트 중심의 프로그래밍 모델에서 먼저 이벤트가 발생한 후 실행할 코드를 작성한 다음 코드를 함수에 넣은 다음 마지막으로 함수를 발신자에게 전달한 다음 나중에 발신자 기능으로 호출하십시오.
JavaScript에서 함수는 격리 된 정의가 아닙니다. 또한 선언 된 범위의 맥락을 기억합니다. 이 메커니즘을 사용하면 JavaScript 함수가 함수 정의가 위치한 컨텍스트 및 상위 컨텍스트의 모든 변수에 액세스 할 수 있습니다.
콜백 함수를 발신자에게 매개 변수로 전달하면 나중에 함수가 호출됩니다. 콜백 함수를 정의하는 범위가 종료 되더라도 콜백 함수가 호출되면 종료 된 스코프 및 상위 스코프의 모든 변수에 여전히 액세스 할 수 있습니다. 마지막 예제와 마찬가지로 콜백 함수는 jQuery의 Click () 내부에서 호출되지만 여전히 ClickCount 변수에 액세스 할 수 있습니다.
폐쇄의 마법은 앞서 나와 있습니다. 상태 변수를 기능으로 전달하면 상태를 유지하지 않고도 이벤트 중심 프로그래밍을 수행 할 수 있습니다. JavaScript의 폐쇄 메커니즘은이를 유지하는 데 도움이됩니다.
요약
이벤트 중심 프로그래밍은 이벤트 트리거를 통해 프로그램 실행 프로세스를 결정하는 프로그래밍 모델입니다. 프로그래머는 관심있는 이벤트 (일반적으로 이벤트 처리기라고 함)에 대한 콜백 기능을 등록한 다음 시스템은 이벤트가 발생할 때 등록 된 이벤트 핸들러를 호출합니다. 이 프로그래밍 모델에는 기존 차단 프로그래밍 모델이없는 많은 장점이 있습니다. 과거에는 유사한 기능을 구현하려면 다중 프로세스/멀티 스레딩을 사용해야합니다.
JavaScript는 첫 번째 유형의 객체 기능 및 폐쇄 속성으로 인해 강력한 언어로 이벤트 중심 프로그래밍에 매우 적합합니다.