Java - Event-driven vs Multithread 에 관련하여

alwaysrainy의 이미지

자바 이벤트-드리븐 관련 자료를 읽다가 의문이 있어 질문 올립니다.

아래의 소스 코드는 간략하게 웹 서버 데몬을 구현한 것입니다.
클라이언트로부터 요청이 발생할 때마다 쓰레드를 생성하여 병행적으로
처리하는 방식입니다.

while ( true ) {
  final Socket sock = acceptConnection();
  Thread t = new Thread() {
    public void run() {
      HttpRequest req = parseRequest(sock);
      HttpResponse resp = createResponse(req);
      sendResponse(sock, resp);
      sock.close();
    }
  };
  t.start();
}

이러한 구조에서 쓰레드 생성으로 인한 부하를 줄이기 위해서 아래와 같은 구조로
바꾼다고 합니다.

public interface ParseDone {
  public void run(HttpRequest req);
}
void parseRequest(Socket sock, ParseDone done) { ... }
void sendResponse(Socket sock, HttpResponse resp, Runable done) { ... }
 
 
while ( true ) {
  final socket sock = acceptConnection();
  ParseDone parseDone = new ParseDone() {
    public void run(HeepRequest req) {
      HttpResponse resp = createResponse(req);
      Runnable sendResponseDone = new Runnable() {
        public void run() { sock.close(); }
      };
      sendResponse(sock, resp, sendResponseDone);
    }
  };
  parseRequest(sock, parseDone);
}

여기서 parseRequest는 호출되자마자 바로 리턴한다고 문서에 나와있습니다.
이것이 이해가 가지 않는데요.. parseRequest 메소드에서 parseDone 객체의
run 메소드를 호출하여 클라이언트에게 응답 메시지를 전송한 후에야 리턴될 것 같은데..
어째서 바로 리턴된다고 적혀있는 것일까요?

제 짧은 지식으로는 parseRequest 메소드에서 클라이언트에게 응답 메시지를
전송하기 전에는 새로운 클라이언트로부터의 요청이 블록될 것 같은데..

원문을 추가하겠습니다.

<span>자료 출처 - <a href="http://www.bamboo-dht.org/async-tutorial/async-tutorial.pdf" rel="nofollow">http://www.bamboo-dht.org/async-tutorial/async-tutorial.pdf</a></span>
 
public interface ParseDone {
  public void run(HttpRequest req);
}
void parseRequest(Socket sock, ParseDone done) { ... }
void sendResponse(Socket sock, HttpResponse resp, Runable done) { ... }
 
The idea is that parseRequest will now return immediately after being called, and sometime later,
when the request has actually been read off the network and parsed, the run function of the ParseDone
object passed into parseRequest will be called. Likewise, sendResponse will also return immediately,
and the run function of the Runnable object passed into sendResponse will be called later, once
the response has been sent.
Ignore for a moment how these new versions of parseRequest and sendResponse are implemented,
and consider only how we might use them. For example, we could rewrite the web server’s main
loop like this:
 
while ( true ) {
  final socket sock = acceptConnection();
  ParseDone parseDone = new ParseDone() {
    public void run(HeepRequest req) {
      HttpResponse resp = createResponse(req);
      Runnable sendResponseDone = new Runnable() {
        public void run() { sock.close(); }
      };
      sendResponse(sock, resp, sendResponseDone);
    }
  };
  parseRequest(sock, parseDone);
}

답변 부탁드리겠습니다.

dormael의 이미지

아마도 원문에서 설명하고자 하는게 이런 내용이 아닐까 싶습니다.

하나의 IO(주로 네트웍 IO)에 대해서 하나의 쓰레드를 할당하는 방법은 매우 비효율 적입니다.
원문에 보면 대부분의 OS에서 수백개 이상의 쓰레드를 생성하면 성능이 많이 떨어진다고 하는것 같네요.

이런 비효율 적인 부분을 개선하기 위해 어플리케이션의 구조를 이벤트 드리븐 방식으로 변경합니다.

자바에서 이벤트 방식을 이용하기 위해서는 큐와, 쓰레드가 필요합니다.
물론 제한된 혹은 단 한개의 쓰레드 겠지요.
효율을 높이기 위해서는 동적인 생성도 어느 정도는 필요할 테구요.

parseRequest,sendResponse 메소드는 요청이 불린 직후 리턴하기 위해서 인자로 받은 내용을 큐에 넣습니다.
그러면 미리 생성되어 있던 이벤트 처리 쓰레드가 큐에 들어가 있는 내용들을 순차적으로 가져와서 ParseDone의 run메소드를 호출합니다. 한번에 하나씩 이겠죠. 물론 이벤트 처리 쓰레드가 여러개면 한번에 꼭 한개는 아닐겁니다.

이와 같은 내용을 구현하려면 멀티쓰레드 환경에서의 동기화와 관련된 부분을 보셔야 합니다.

실제로 자바의 대부분 이벤트 처리들이 이렇게 이루어지는걸로 알고 있습니다.

물론 (Input, 로직처리, Output)이 한 쓰레드에서 순차적으로 실행이 되는것도 효율을 그렇게 높이지 못합니다.
적은수의 쓰레드가 느린 Input, Output에 시간을 소비하면 큐에있는 다른 것들이 처리되는 시간이 늦어집니다.

그래서 보통은 세가지를 처리하는 쓰레드를 따로 두고 이벤트를 셋으로 분리해서 많이 씁니다.
여기에 Input, Output으로 인한 시간 낭비를 줄이고 적은수의 쓰레드로도 빠른 응답을 얻기위해 고전적인IO 대신에 NIO를 쓰게 됩니다.

이제 남은것은 로직처리 지연을 줄이기 위해 충분한 수의 쓰레드를 결정하는 일만 남았습니다.
이건 각자가 찾아야 되구요.

실제로 이와 같은 구조를 프레임웍화 해서 만들어 놓은게 있습니다.

APACHE의 MINA(http://mina.apache.org)라는 것이구 자랑스럽게도(^^) 우리나라 분이 만들었습니다.

-- Signature --
青い空大好き。
蒼井ソラもっと好き。
파란 하늘 너무 좋아.
아오이 소라 더좋아.

blueskya의 이미지

정확한 내용, 적절한 설명... -_-b

동기화 쪽을 자세히 본다면 적절할듯....

이러한 부분의 문제들은 과거 자바뉴스레터에서 개선점들이 소개되었던것으로 기억하는데...

오래되고, 자바도 않쓰다보니 가물가물하네요 ^^;;

----------------------------------------------------------------------
인생 뭐있어? 백수로 사는거야~ 가는거야~

----------------------------------------------------------------------
인생 뭐있어? 백수로 사는거야~ 가는거야~

alwaysrainy의 이미지

역시 큐에 넣고 쓰레드에서 이를 순차적으로 처리해야 하는거군요.. 답변에 감사드립니다 ^^

세계는 넓고, 할일은 많다.

---------------------------------------
세계는 넓고, 할일은 많다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.