개요

SSAFY 계절학기 강의 수강 중 싱글스레드에서 비동기 요청을 할 수 있다는 내용이 있었는데, 필자가 개발하면서 싱글 스레드 환경에서 비동기 요청을 한 기억이 없어서 그런지 잘 이해가 되지 않았다. 이를 이해하고자 문서를 작성해본다.

자바스크립트에서 싱글 스레드와 비동기 요청

아래와 같이 “싱글스레드 비동기” 라는 키워드로 구글에 검색을 해봤다. 그러나 이 부분은 자바스크립트 언어가 어떻게 싱글 스레드에서 비동기 요청 처리를 가능하게 하는 것인지 말해주는 내용이 대다수 였다. 글들을 읽어보면 결국에는 자바스크립트 언어 자체는 싱글 스레드로 동작하는 것이고, 비동기 요청의 경우 Browser API를 통해 비동기 요청을 처리 후 콜백 처리를 해주는 것으로 이해했다.

따라서, 자바스크립트도 결국에는 완전한 싱글 스레드가 아니라고 생각했다.

그렇다면 완전한 싱글스레드 환경에서 비동기 요청은 가능한 것일까?

알고리즘을 풀 때 처럼 main 함수만 있는 환경에서도 비동기 요청이 가능할 지 궁금했다.

대표적인 비동기 요청 사례인 File I/O를 통해 이를 알아보자.

동기 및 비동기 I/O

동기 파일 I/O에서 스레드는 I/O 작업을 시작하고 I/O 요청이 완료될 때까지 즉시 대기 상태로 돌입합니다. 비동기 파일 I/O를 수행하는 스레드는 적절한 함수를 호출하여 커널에 I/O 요청을 보냅니다. 커널에서 요청을 수락하는 경우, 커널이 스레드에 I/O 작업이 완료되었다는 신호를 보낼 때까지 호출 스레드가 다른 작업을 계속 처리합니다. 그런 다음 현재 작업을 중단하고 필요에 따라 I/O 작업에서 데이터를 처리합니다.

 

아래는 동기 I/O와 비동기 I/O를 그림으로 표현한 것이다.

 

간단하게 정리해보면, I/O 처리의 경우 커널모드 스레드에서 수행된다. 싱글 스레드라고 믿었던 프로그램도 사실은 커널모드 스레드를 통해 I/O 작업을 수행하고 있다. 따라서 위와 같은 파일 I/O 작업의 경우 싱글스레드 프로그램에서도 비동기 요청이 가능하다. 다만, 파일 I/O의 경우 커널모드의 스레드를 이용하므로, 이와 같이 타 스레드에 작업을 위임하지 않는 이상 싱글 스레드에서 비동기 요청은 불가능하다고 생각한다.

싱글 스레드에서 비동기, 효율적인가?

서비스를 개발하면서 싱글 스레드에서 비동기 요청을 하는 경우를 많이 이용해본 적이 없다. 왜일까? 만약, 파일 읽기 요청과 다른 작업을 함께 수행한다고 생각해보면 굉장히 불편할 것이라고 생각한다. 다른 작업을 수행하면서 수시로 커널에 I/O가 완료 되었는지 물어봐야 할 것이고, 에러처리도 어려울 것이다.

비동기 처리 아키텍쳐

Spring, Android와 같은 많은 프레임워크에 비동기 처리를 지원하는 API를 포함하거나, 라이브러리 형태로 사용하기 좋게끔 만들어져 있다. 이러한 라이브러리들은 어떤 구조로 만들어져 있을까? 대표적인 비동기 요청 라이브러리인 Spring WebClient를 통해 알아보자.

Spring WebFlux includes a client to perform HTTP requests with. WebClient has a functional, 
fluent API based on Reactor, see Reactive Libraries, which enables declarative composition 
of asynchronous logic without the need to deal with threads or concurrency. It is fully 
non-blocking, it supports streaming, and relies on the same codecs that are also used to 
encode and decode request and response content on the server side.

Spring WebFlux에 내장된 WebClient의 경우 netty를 기반으로 만들어졌다고 한다. netty는 Reactor Pattern으로 만들어졌다고 하는데, Reactor Pattern에 대해서도 간단히 알아보자.

Reactor Pattern

하나 이상의 클라이언트로부터의 요청을 동시 처리하기 위해서 사용하는 패턴이다.

어플리케이션에서 이벤트를 처리하기 위한 루프를 도는 것이 아니라, 이벤트에 반응하는 객체(reactor)를 만들고, 이벤트가 발생하면 어플리케이션 대신 reactor가 반응하여 처리하는 것이다.

정리

이와 같이 싱글 스레드에서 비동기 요청을 할 수는 있지만, 사용되지 않는 이유가 있는 것 같다. 결론을 내보자면 아래와 같다.

  • 싱글 스레드에서 일부 작업의 경우 비동기 요청이 가능하다.
  • Reactor Pattern이 등장 한 것처럼 비동기 요청의 경우 멀티 스레드를 이용하여 구현하는 것이 효율적일 것이다.

Reference

동기 및 비동기 I/O - Win32 apps

WebClient :: Spring Framework

리액터패턴 / 프로액터패턴

 

문제

문제 설명

네트워크란 컴퓨터 상호 간에 정보를 교환할 수 있도록 연결된 형태를 의미합니다. 예를 들어, 컴퓨터 A와 컴퓨터 B가 직접적으로 연결되어있고, 컴퓨터 B와 컴퓨터 C가 직접적으로 연결되어 있을 때 컴퓨터 A와 컴퓨터 C도 간접적으로 연결되어 정보를 교환할 수 있습니다. 따라서 컴퓨터 A, B, C는 모두 같은 네트워크 상에 있다고 할 수 있습니다.

컴퓨터의 개수 n, 연결에 대한 정보가 담긴 2차원 배열 computers가 매개변수로 주어질 때, 네트워크의 개수를 return 하도록 solution 함수를 작성하시오.

제한사항

  • 컴퓨터의 개수 n은 1 이상 200 이하인 자연수입니다.
  • 각 컴퓨터는 0부터 n-1인 정수로 표현합니다.
  • i번 컴퓨터와 j번 컴퓨터가 연결되어 있으면 computers[i][j]를 1로 표현합니다.
  • computer[i][i]는 항상 1입니다.

입출력 예

n computers return

3 [[1, 1, 0], [1, 1, 0], [0, 0, 1]] 2
3 [[1, 1, 0], [1, 1, 1], [0, 1, 1]] 1

입출력 예 설명

예제 #1

아래와 같이 2개의 네트워크가 있습니다.

예제 #2

아래와 같이 1개의 네트워크가 있습니다.

풀이

DFS 또는 BFS로 풀 수 있는 문제로, 나는 BFS를 사용해서 풀었다. 각 노드들을 순회하면서, 만약 방문하지 않은 노드라면 큐에 넣은 후 연결된 노드를 모두 탐색하여 방문처리 해준다. 방문처리가 끝났다면 answer 값을 증가 시켜주면 된다.

코드

import java.util.LinkedList;
import java.util.Queue;

class Solution {
    public int solution(int n, int[][] computers) {
        int answer = 0;
        boolean[] visited = new boolean[n];
        Queue<Integer> queue = new LinkedList<>();
        for (int i = 0; i < n; i++) {
            if (!visited[i]) {
                visited[i] = true;
                queue.add(i);
                while (!queue.isEmpty()) {
                    int idx = queue.poll();
                    for (int j = 0; j < computers[idx].length; j++) {
                        if (!visited[j] && computers[idx][j] == 1) {
                            visited[j] = true;
                            queue.add(j);
                        }
                    }
                }
                answer++;
            }
        }

        return answer;
    }
}

컴퓨터 공학 전공이 아닌 학교 친구가 통신에 대해서 여쭤봐서, 실시간으로 안드로이드 기기와 통신할 수 있는 방법을 알아야 했는데, 내 컴퓨터를 웹서버로 만들고 외부에서 접속하는 방법을 간단하게 알아보았다.

 

1. apache 설치 및 환경설정

 

https://www.apachelounge.com/download/ 아파치 공식 웹 사이트에 접속하여 아파치를 다운로드한다.

 

다운로드 후 apache24 폴더를 원하는 경로에 지정해준다. 나는 D:\Apache24 로 설정했다.

그 후 conf 폴더로 이동하여 httpd.conf 에서 몇가지 설정을 해준다.

 

폴더 경로를 아래와 같이 변경해준다.

Define SRVROOT "d:/Apache24"

그리고 포트를 변경하고 싶다면 LISTEN 을 검색한다. 기본으로 80으로 설정되어 있지만, 나는 8080으로 변경해줬다.

Listen 8080

 

그 후 D:\Apache24\bin 폴더에서 httpd.exe 파일을 실행해준다.

 

localhost에 접속하여 화면이 잘 나오는것을 확인하자.

 

2. 포트포워딩 설정하기

 

여기까지 설정이 되었다면 다음은 포트포워딩을 할 차례이다. 

 

필자는 딜라이브 공유기를 사용하므로 딜라이브 공유기 환경설정 페이지로 이동하겠다.

 

http://192.168.200.254/ 로 접속하여 네트워크 > 포트 포워딩 페이지에서 아래와 같이 설정한다.

 

설명 : 본인이 원하는 이름으로 설정. 나는 develop으로 설정했다.

ip주소 : cmd 창에서 ipconfig 입력 후 IPv4 주소를 입력한다.

포트번호 : 위에 설정한 포트번호와 같은 번호로 입력한다.

프로토콜 : UDP, TCP 중 선택가능하다. 나는 TCP로 선택했다.

 

마지막으로, 네이버에 공인IP 검색하여 공인IP를 알아낸다.

 

 

공인IP:8080 검색하여 접속하면 끝이다.

 

이번에는 웹서버 연결으로 외부 망 접속을 시도했으나. 조만간 소켓을 통해서도 연결하는 방법을 공부해봐야겠다..

'TIL' 카테고리의 다른 글

2021.09.09  (0) 2021.09.10
2021.09.08  (0) 2021.09.08
[TIL] python OpenCV - threshold 함수로 경계선 얻기  (0) 2021.07.26
[TIL] python OpenCV - 1  (1) 2021.07.26
C언어에서 배열의 크기를 변수로 선언할 수 있을까?  (5) 2019.10.29

+ Recent posts