Node.js에 대한 Haskell 응답은 무엇입니까?


217

Erlang 커뮤니티는 기본적으로 비 블로킹 I / O를 수행하고 둘 이상의 프로세서 (노드 .js에 내장되지 않은 프로세서)로 배포를 쉽게 확장 할 수있는 방법이 있기 때문에 Node.js를 부러워하지 않는다고 생각합니다. http://journal.dedasys.com/2010/04/29/erlang-vs-node-jsNode.js 또는 Erlang에 대한 자세한 내용

하스켈은 어떤가요? Haskell은 Node.js의 이점 중 일부, 즉 멀티 스레드 프로그래밍에 의존하지 않고 I / O를 차단하지 않는 깨끗한 솔루션을 제공 할 수 있습니까?


Node.js에는 매력적인 것들이 많이 있습니다

  1. 이벤트 : 스레드 조작이 없으며 프로그래머는 스냅 프레임 워크에서와 같이 콜백 만 제공합니다.
  2. 콜백은 단일 스레드에서 실행되도록 보장됩니다. 경쟁 조건이 없습니다.
  3. 훌륭하고 간단한 유닉스 친화적 API. 보너스 : 탁월한 HTTP 지원. DNS도 가능합니다.
  4. 모든 I / O는 기본적으로 비동기입니다. 이렇게하면 잠금을 피하기가 더 쉬워집니다. 그러나 콜백에서 너무 많은 CPU 처리는 다른 연결에 영향을 미칩니다 (이 경우 작업은 더 작은 하위 작업으로 분할되고 다시 예약되어야 함).
  5. 클라이언트 측과 서버 측에 동일한 언어. jQuery와 Node.js는 이벤트 프로그래밍 모델을 공유하지만 나머지는 매우 다릅니다. 서버 측과 클라이언트 측 사이에서 코드를 공유하는 방법을 볼 수는 없습니다. 실제로 유용합니다.)
  6. 이 모든 것이 단일 제품으로 포장됩니다.

17
대신 프로그래머 에게이 질문을해야한다고 생각합니다 .
Jonas

47
코드를 포함하지 않으면 주관적인 질문이되지 않습니다.
gawi

20
node.js에 대해 많이 모르지만 질문에 대해 한 가지 나에게 충격을주었습니다. 왜 스레드의 전망이 그렇게 불쾌합니까? 스레드는 멀티플렉싱 I / O에 대한 올바른 솔루션이어야합니다. 여기서는 Erlang의 프로세스를 포함하여 스레드라는 용어를 광범위하게 사용합니다. 아마도 잠금 및 변경 가능한 상태가 걱정됩니까? 응용 프로그램에 더 적합한 경우 메시지 전달 또는 트랜잭션을 사용하십시오.
Simon Marlow

9
@gawi 나는 프로그래밍하기가 쉽지 않다고 생각합니다. 선점없이 기아와 긴 대기 시간의 가능성을 처리해야합니다. 기본적으로 스레드는 웹 서버에 적합한 추상화입니다. 비동기 I / O를 처리 할 필요가 없으며 이와 관련된 모든 어려움은 스레드에서 수행하면됩니다. 덧붙여서, 나는 당신이 흥미로울만한 Haskell의 웹 서버에 관한 논문을 썼습니다 : haskell.org/~simonmar/papers/web-server-jfp.pdf
Simon Marlow

3
"콜백은 단일 스레드에서 실행되도록 보장합니다. 경쟁 조건이 없습니다." 잘못된. Node.js에서 경쟁 조건을 쉽게 가질 수 있습니다. 하나의 I / O 작업이 다른 I / O 작업보다 먼저 완료되고 BOOM이라고 가정합니다. 무엇 이며 실제로 불가능한 것은 경쟁 조건의 하나의 특정 종류의 메모리에 동일한 바이트, 즉 동시 비 동기화 접근이다.
rightfold

답변:


219

좋아, @gawi가 지적한 node.js 프레젠테이션 을 보았으므로 Haskell이 node.js와 비교하는 방법에 대해 조금 더 말할 수 있습니다. 프리젠 테이션에서 Ryan은 Green Threads의 이점 중 일부에 대해 설명하지만 스레드 추상화의 부족이 단점이 아니라고 말합니다. 특히 Haskell의 맥락에서 그의 입장에 동의하지 않습니다. 스레드가 제공하는 추상화는 서버 코드를보다 쉽고 정확하게 작성하는 데 필수적이라고 생각합니다. 특히:

  • 연결 당 하나의 스레드를 사용하면 모든 클라이언트를 동시에 처리하는 코드를 작성하는 대신 단일 클라이언트와의 통신을 표현하는 코드를 작성할 수 있습니다 . 스레드가있는 여러 클라이언트를 처리하는 서버는 단일 클라이언트를 처리하는 서버와 거의 동일하게 보입니다. 가장 큰 차이점은 fork전자 의 어딘가에 있다는 것입니다. 구현하는 프로토콜이 전혀 복잡하지 않으면 여러 클라이언트의 상태 시스템을 동시에 관리하는 것이 까다로울 수 있지만 스레드를 사용하면 단일 클라이언트와의 통신을 스크립팅 할 수 있습니다. 코드는 이해하기 쉽고 이해하고 유지 관리하기가 더 쉽습니다.

  • 단일 OS 스레드의 콜백은 선점 형 멀티 태스킹과 달리 협동 멀티 태스킹입니다. 협동 멀티 태스킹의 주요 단점은 프로그래머가 기아가 없는지 확인해야한다는 점입니다. 모듈성을 잃습니다. 한곳에서 실수하면 전체 시스템을 망칠 수 있습니다. 이것은 실제로 걱정할 필요가 없으며 선점은 간단한 솔루션입니다. 또한 콜백 간의 통신이 불가능합니다 (교착 상태가 발생 함).

  • Haskell에서는 동시성이 어렵지 않습니다. 대부분의 코드가 순수하고 구성에 의해 스레드로부터 안전하기 때문입니다. 간단한 의사 소통 기본 요소가 있습니다. 부작용이없는 언어보다 Haskell에서 동시성을 사용하여 발을 딛는 것이 훨씬 어렵습니다.


42
좋아, 그래서 node.js는 두 가지 문제에 대한 해결책이라는 것을 알았습니다. 1-동시성은 대부분의 언어에서 어렵고, 2는 OS 스레드를 사용하는 것이 광범위합니다. Node.js 솔루션은 이벤트 기반 동시성 (w / libev)을 사용하여 스레드 간의 통신을 피하고 OS 스레드의 확장 성 문제를 방지합니다. Haskell은 순도 때문에 문제 # 1이 없습니다. # 2의 경우 Haskell에는 경량 스레드 + 이벤트 관리자가 있으며 대규모 컨텍스트에 대해 최근 GHC에서 최적화되었습니다. 또한 Javascript를 사용하는 것은 Haskell 개발자에게 플러스로 인식 될 수 없습니다. Snap Framework를 사용하는 일부 사람들에게는 Node.js가 "나쁜"것입니다.
gawi

4
요청 처리는 대부분 상호 의존적 인 작업 순서입니다. 모든 차단 작업에 콜백을 사용하는 것이 번거로울 수 있다는 데 동의합니다. 스레드는 이것에 대한 콜백보다 더 적합합니다.
gawi

10
네! 그리고 GHC 7의 새로운 I / O 멀티플렉싱은 Haskell의 서버 작성을 훨씬 더 향상시킵니다.
andreypopp

3
첫 번째 요점은 (외부인으로서) 나에게 이해가되지 않습니다 ... node.js에서 요청을 처리 할 때 콜백은 단일 클라이언트를 처리합니다. 상태 관리는 여러 프로세스로 확장 할 때 걱정할 일이되며 사용 가능한 라이브러리를 사용하는 것은 매우 쉽습니다.
Ricardo Tomasi 2016 년

12
별도의 문제가 아닙니다. 이 질문이 Haskell에서 작업에 가장 적합한 도구를 검색하거나 Haskell에 작업에 대한 우수한 도구가 있는지 확인하는 경우 Haskell은 멀티 스레드 프로그래밍이 적합하지 않다는 암시적인 가정에 도전해야합니다. Don Stewart가 지적했듯이 스레드는 다소 다릅니다. Haskell 커뮤니티가 Node.js에 대해 질투하지 않는 이유를 설명하는 답변은이 질문에 대해 많은 주제를 다루고 있습니다. gawi의 답변은 이것이 그의 질문에 대한 적절한 답변임을 시사합니다.
AndrewC

154

Haskell은 Node.js의 이점 중 일부, 즉 멀티 스레드 프로그래밍에 의존하지 않고 I / O를 차단하지 않는 깨끗한 솔루션을 제공 할 수 있습니까?

예, 사실 Haskell에서 이벤트와 스레드가 통합되었습니다.

  • 명시적인 경량 스레드 (예 : 단일 랩톱에서 수백만 개의 스레드)로 프로그래밍 할 수 있습니다.
  • 또는; 확장 가능한 이벤트 알림을 기반으로 비동기 이벤트 중심 스타일로 프로그래밍 할 수 있습니다.

스레드는 실제로 이벤트 측면에서 구현되며 원활한 스레드 마이그레이션, 문서화 된 성능 및 응용 프로그램을 통해 여러 코어에서 실행됩니다.

예를 들어

32 개 코어에서 동시 수집

대체 텍스트

Haskell에는 이벤트와 스레드가 모두 있으며 모든 이벤트는 후드 아래에 있습니다.

구현을 설명 하는 논문읽으십시오 .


2
감사. 이 모든 것을 소화해야합니다 ... 이것은 GHC에 특정한 것 같습니다. 괜찮습니다. 하스켈 언어는 언젠가 GHC가 컴파일 할 수있는 것입니다. 비슷한 방식으로, Haskell "플랫폼"은 GHC 런타임입니다.
gawi

1
@gawi : 그것과 다른 모든 패키지가 번들로 제공되므로 즉시 사용할 수 있습니다. 그리고 이것은 제가 CS 과정에서 본 것과 같은 이미지입니다. 그리고 가장 좋은 점은 Haskell에서 자신의 프로그램에서 비슷한 멋진 결과를 얻는 것이 어렵지 않다는 것입니다.
Robert Massaioli

1
안녕하세요, 이런 질문에 답할 때 최고 (Warp)를 수행하는 haskell 웹 서버에 연결할 수 있다고 생각하십니까? 여기에서 Node.js를 상대로 매우 관련 벤치 마크는 다음과 같습니다 yesodweb.com/blog/2011/03/...
그렉 웨버

4
이론 상으로는. 하스켈 "경량 스레드"는 생각만큼 가볍지 않습니다. 녹색 스레드를 예약하는 것보다 epoll 인터페이스에 콜백을 등록하는 것이 훨씬 저렴하지만 물론 OS 스레드보다 저렴하지만 무료는 아닙니다. 100.000을 생성하면 약을 사용합니다. 350MB의 메모리와 시간이 걸립니다. node.js와 100.000 연결을 시도하십시오. 전혀 문제 없습니다. ghc가 후드 ​​아래에서 epoll을 사용하므로 epoll을 직접 사용하는 것보다 빠를 수 없으므로 속도가 빠르지 않으면 마술입니다. 하지만 쓰레드 인터페이스를 사용한 프로그래밍은 매우 훌륭하다.
Kr0e

3
또한 새로운 IO 관리자 (ghc)는 (m log n) 복잡도를 갖는 스케줄링 알고리즘을 사용합니다 (여기서 m은 실행 가능한 스레드 수 및 n 총 스레드 수). Epoll에는 복잡성 k가 있습니다 (k는 읽기 / 쓰기 가능한 fd의 수 =. 따라서 ghc는 모든 복잡성에 대해 O (k * m log n)를 가지므로 트래픽이 많은 연결에 직면하면 그리 좋지 않습니다 Windows 성능에 대해 이야기하지 말고 Node.js는 IOCP를 사용하기 때문에 훨씬 빠릅니다.
Kr0e

20

먼저, node.js가 이러한 콜백을 모두 노출시키는 것이 옳은 일이라는 견해는 없습니다. 당신은 CPS (연속 전달 스타일)로 프로그램을 작성하게되는데, 그 변환을 수행하는 것이 컴파일러의 일이라고 생각합니다.

이벤트 : 스레드 조작이 없으며 프로그래머는 스냅 프레임 워크에서와 같이 콜백 만 제공합니다.

따라서이를 염두에두고 원하는 경우 비동기 스타일을 사용하여 작성할 수 있지만 그렇게하면 요청 당 하나의 스레드로 효율적인 동기 스타일로 작성하는 것을 놓칠 수 있습니다. Haskell은 동기 코드에서 특히 다른 언어와 비교할 때 엄청나게 효율적입니다. 모든 이벤트가 아래에 있습니다.

콜백은 단일 스레드에서 실행되도록 보장됩니다. 경쟁 조건이 없습니다.

node.js에 여전히 경쟁 조건이있을 수 있지만 더 어렵습니다.

모든 요청은 자체 스레드에 있습니다. 다른 스레드와 통신해야하는 코드를 작성할 때 haskell의 동시성 프리미티브 덕분에 스레드 안전성을 유지하는 것이 매우 간단합니다.

훌륭하고 간단한 유닉스 친화적 API. 보너스 : 탁월한 HTTP 지원. DNS도 가능합니다.

해킹을 살펴보고 직접 확인하십시오.

모든 I / O는 기본적으로 비동기 적입니다 (그러나 때때로 성 가실 수 있습니다). 이렇게하면 잠금을 피하기가 더 쉬워집니다. 그러나 콜백에서 너무 많은 CPU 처리는 다른 연결에 영향을 미칩니다 (이 경우 작업은 더 작은 하위 작업으로 분할되고 다시 예약되어야 함).

그러한 문제는 없습니다. ghc는 실제 OS 스레드에 작업을 배포합니다.

클라이언트 측과 서버 측에 동일한 언어. JQuery와 Node.js는 이벤트 프로그래밍 모델을 공유하지만 나머지는 매우 다릅니다. 서버 측과 클라이언트 측 사이에서 코드를 공유하는 방법을 볼 수는 없습니다. 실제로 유용합니다.)

하스켈이 여기서 이길 수는 없습니다 ... 그렇죠? http://www.haskell.org/haskellwiki/Haskell_in_web_browser 다시 생각해보십시오 .

이 모든 것이 단일 제품으로 포장됩니다.

ghc를 다운로드하고 cabal을 실행하십시오. 모든 요구에 맞는 패키지가 있습니다.


나는 단지 악마의 옹호자를하고 있었다. 그렇습니다, 나는 당신의 요점에 동의합니다. 클라이언트 측 및 서버 측 언어 통일을 제외하고. 기술적으로 실현 가능하다고 생각하지만 오늘날 모든 Javascript 생태계 (JQuery 및 친구)를 대체 할 수는 없다고 생각합니다. Node.js 지지자들이 제시 한 주장이지만, 그것이 중요하지 않다고 생각합니다. 프리젠 테이션 레이어와 백엔드간에 많은 양의 코드를 공유해야합니까? 우리는 정말로 한 언어 만 아는 프로그래머를 목표로 삼고 있습니까?
gawi

실제 승리는 서버와 클라이언트 쪽 모두에서 페이지를 렌더링하여 실시간 페이지를보다 쉽게 ​​만들 수 있다는 것입니다.
dan_waterworth

@dan_waterworth 정확하게, 유성 또는 derby.js를
mb21

1
@gawi 우리는 85 %의 코드가 클라이언트와 서버간에 공유되는 프로덕션 서비스를 제공합니다. 이것은 커뮤니티에서 범용 JavaScript로 알려져 있습니다. React를 사용하여 서버에서 컨텐츠를 동적으로 렌더링하여 클라이언트에서 처음으로 유용한 렌더링 시간을 줄입니다. 브라우저에서 Haskell을 실행할 수 있다는 것을 알고 있지만 동일한 코드베이스를 사용하여 서버 측 및 클라이언트 측 렌더링을 허용하는 "유니버설 Haskell"모범 사례를 모릅니다.
Eric Elliott

8

필자는 개인적으로 Node.js와 콜백을 사용한 프로그래밍이 불필요하게 저수준이며 약간 부 자연스러운 것으로 본다. GHC에서 제공되는 것과 같은 런타임이 콜백을 처리하고 매우 효율적으로 수행 할 수있는 경우 콜백을 사용하여 프로그램하는 이유는 무엇입니까?

그 동안 GHC 런타임이 크게 향상되었습니다. 이제 MIO 라는 "새로운 새 IO 관리자"기능이 있습니다. 여기서 "M"은 제가 생각하는 멀티 코어를 나타냅니다. 기존 IO 관리자를 기반으로 구축되며 주요 목표는 4 개 이상의 코어 성능 저하 원인을 극복하는 것입니다. 이 백서에 제공된 성능 수치는 매우 인상적입니다. 자신을보십시오 :

Haskell의 현실적인 HTTP 서버는 Mio를 사용하여 20 개의 CPU 코어로 확장하여 이전 버전의 GHC를 사용하는 동일한 서버에 비해 최대 6.5 배의 최고 성능을 달성합니다. Haskell 서버의 대기 시간도 개선되었습니다. [...] 보통로드시 이전 버전의 GHC와 비교할 때 예상 응답 시간을 5.7x 단축

과:

또한 Mio를 통해 McNettle (하스켈로 작성된 SDN 컨트롤러)은 40 개 이상의 코어로 효과적으로 확장 할 수 있고 단일 시스템에서 초당 2 천만 건 이상의 새로운 요청에 도달 할 수 있으며, 따라서 기존의 모든 SDN 컨트롤러 중에서 가장 빠른 것으로 나타났습니다 .

Mio는이를 GHC 7.8.1 릴리스로 만들었습니다. 필자는 개인적으로 이것을 하스켈 성능의 주요 진전으로보고 있습니다. 이전 GHC 버전과 7.8.1에 의해 컴파일 된 기존 웹 애플리케이션 성능을 비교하는 것은 매우 흥미로울 것입니다.


6

IMHO 이벤트는 좋지만 콜백을 통한 프로그래밍은 좋지 않습니다.

웹 응용 프로그램의 코딩 및 디버깅을 특별하게 만드는 대부분의 문제는 확장 가능하고 유연하게 만드는 것에서 비롯됩니다. HTTP의 가장 중요한 무국적 속성. 탐색 기능은 향상되지만 IO 요소 (이 경우 웹 서버)가 응용 프로그램 코드에서 다른 처리기를 호출하는 제어 역전이 발생합니다. 콜백은 가변 범위를 공유하지 않으며 내비게이션의 직관적 인보기가 손실되므로이 이벤트 모델 또는 콜백 모델 (보다 정확하게 말하면)은 악몽입니다. 사용자가 다른 문제 중에서 앞뒤로 탐색 할 때 가능한 모든 상태 변경을 방지하는 것은 매우 어렵습니다.

문제는 이벤트 모델이 잘 작동하는 GUI 프로그래밍과 유사하지만 GUI에는 탐색이없고 뒤로 단추가 없다고 말할 수 있습니다. 이는 웹 애플리케이션에서 가능한 상태 전이를 증가시킵니다. 이러한 문제를 해결하려는 시도의 결과는 문제의 근본을 의심하지 않고 복잡한 구성을 가진 복잡한 구성을 가진 무거운 프레임 워크입니다. 식별자를 연결하여 구성됩니다.

탐색 및 REST-fulness를 유지하면서 상태 관리 문제를 해결하는 ocsigen (ocaml) 해변 (smalltalk) WASH (discontinued, Haskell) 및 mflow (Haskell)와 같은 순차적 기반 프레임 워크가 있습니다. 이 프레임 워크 내에서 프로그래머는 탐색을 프로그램이 페이지를 전송하고 단일 스레드에서 응답을 기다리는 명령 시퀀스로 표현할 수 있으며 변수가 범위 내에 있고 뒤로 단추가 자동으로 작동합니다. 이것은 본질적으로 내비게이션이 프로그래머에게 명확하게 보여지는 더 짧고, 더 안전하고, 더 읽기 쉬운 코드를 생성합니다. (공정한 경고 : 저는 mflow의 개발자입니다)


node.js에서 콜백은 데이터베이스와 같은 비동기 I / O 처리에 사용됩니다. 당신은 흥미롭지 만 질문에 대답하지 않는 다른 것에 대해 이야기하고 있습니다.
Robin Green

네 말이 맞아 : 그것은, 내가 희망, 당신의 반대를 충족 답변이 3 년 걸렸다 github.com/transient-haskell
agocorona

Node는 이제 비동기 함수를 지원합니다. 즉, 실제로 비동기적인 명령형 코드를 작성할 수 있습니다. 그것은 후드 아래 약속을 사용합니다.
Eric Elliott

5

이 문제는 1) Haskell이 이미이 문제를 훨씬 더 나은 방법으로 해결했고 2) Erlang과 거의 같은 방식으로 문제를 해결 한 것입니다. 다음은 노드에 대한 벤치 마크입니다. http://www.yesodweb.com/blog/2011/03/preliminary-warp-cross-language-benchmarks

Haskell에 4 개의 코어를 제공하면 단일 응용 프로그램에서 초당 100k (단순) 요청을 수행 할 수 있습니다. 노드는 많은 작업을 수행 할 수 없으며 코어 전체에서 단일 애플리케이션을 확장 할 수 없습니다. Haskell 런타임은 비 블로킹이기 때문에이 작업을 수행하기 위해 아무 것도 할 필요가 없습니다. 런타임에 비 차단 IO가 내장 된 유일한 다른 (상대적으로 일반적인) 언어는 Erlang입니다.


14
어리석은? 문제는 "하스켈에 응답이 있는가"가 아니라 "하스켈에 대한 응답이 있는가"입니다. 질문을 받았을 때, GHC 7은 출시되지 않았기 때문에 Haskell은 아직 "게임에"포함되지 않았습니다 (Snap과 같은 libev를 사용하는 프레임 워크 제외). 그 외에는 동의합니다.
gawi

1
이 답변을 게시했을 때 이것이 사실인지는 알지 못하지만 이제 실제로 노드 앱이 코어 전체에서 쉽게 확장되도록하는 노드 모듈이 있습니다. 또한 해당 링크는 단일 코어에서 실행되는 node.js와 4 개의 코어에서 실행되는 haskell을 비교합니다. 더 공정한 구성으로 다시 실행되는 것을보고 싶지만 아쉽게도 github 저장소가 사라졌습니다.
Tim Gautier

2
4 개 이상의 코어를 사용하는 Haskell은 응용 프로그램의 성능을 저하시킵니다. 이 문제에 대한 논문이 있었지만 현재 활발히 연구 중이지만 여전히 문제입니다. 따라서 16 개의 코어 서버에서 16 개의 Node.js 인스턴스를 실행하는 것이 + RTS -N16을 사용하는 단일 ghc 애플리케이션보다 훨씬 좋을 것입니다.이 런타임 버그로 인해 + RTS -N1보다 느릴 것입니다. 많은 OS 스레드와 함께 사용할 때 속도가 느려지는 IOManager를 하나만 사용하기 때문입니다. 나는 그들이이 버그를 고치기를 희망하지만 그 이후로 존재하므로 많은 희망을 갖지 못했을 것입니다 ...
Kr0e

이 답변을 보는 사람은 Node가 단일 코어에서 100k 간단한 요청을 쉽게 처리 할 수 ​​있으며 많은 코어에서 Stateless Node 응용 프로그램을 쉽게 확장 할 수 있다는 것을 알고 있어야합니다. pm2 -i max path/to/app.js사용 가능한 코어를 기반으로 최적의 인스턴스 수로 자동 확장됩니다. 또한 노드는 기본적으로 비 차단입니다.
Eric Elliott

1

1
이것이 어떻게 질문에 대답합니까?
dfeuer

1
@dfeuer 링크는 다음과 같이 읽습니다. Snap Haskell Web Framework가 libev를 삭제했습니다. 왜 포맷이 실패하는지 모르겠습니다. 노드 서버 런타임은 시작할 때 Linux libev에 관한 것이 었으며 Snap Web FrameWork도 마찬가지였습니다. Haskell with Snap은 nodejs가 포함 된 ECMAscript와 유사하므로 Snap이 nodejs와 함께 진화하는 방식이 Haskell보다 관련성이 높아서이 맥락에서 ECMAscript와 더 정확하게 비교할 수 있습니다.
Chawathe Vipul S 2016
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.