안녕하세요 작년 8월에 인서울 하위권 수준 컴공을 졸업한 26살 취준생입니다. 요즘 진로 관련 고민이 많아, 현실을 객관적으로 파악하고 선택을 해야 할 것 같아서 질문드립니다. 게임 서버 프로그래밍 분야에 늦게 관심이 생겨서 작년부터 공부를 시작했습니다. 작년에 루키스님 C++ 게임 서버 강의를 보고 채팅 서버를 만들었습니다. 6개월 정도가 걸렸는데 저의 C++ 실력이 너무 부족하다는 생각을 많이 했습니다. 그래서 이후에 C++ 관련 공부 (간단한 2D 게임, asio 네트워크 프로그래밍, 알고리즘 등) 등을 했습니다. 공부를 끝내고 올해 2월 정도부터 게임 서버 강의를 다시 보면서 2D MMO 서버를 목표로 프로젝트를 진행하고 있습니다. 현재 고민은 다음과 같습니다. 취준 기간이 너무 길어지고 있는 것 같아서 지금 제가 잘 하고 있는 건지 의문이 듭니다. 요즘 채용 공고를 보니 게임 서버 신입, 특히 C++ 쪽은 정말 절망적일 수준으로 공고가 없어서 계속 준비하는 게 맞나 생각이 듭니다. 서버 신입은 보수적이라 학교 같은 기본적인 스펙이 중요하다고 하셨는데 뛰어난 스펙을 가진 상황이 아니라서 열심히 해도 경쟁력이 있을까 의구심이 듭니다. 지금이라도 방향을 바꿔서 그나마 수요가 있는 웹 개발쪽으로 가는 것도 방법일까요? 취준 기간이 길어지니 이런 부정적인 생각만 늘어나네요. 확실한 정답은 없겠지만 루키스님이 의견 주시면 도움이 많이 될 것 같습니다. 현실적인 답변 부탁드립니다. 감사합니다.
3-B번 보물섬 문제를 풀다가. 각 육지마다 BFS를 하는 것보다, 한 컴포넌트에서 BFS_1로 임의의 한 점에서 가장 먼 점을 찾고, 찾은 가장 먼 점에서 BFS_2로 또 가장 먼 점을 찾으면, 해당 컴포넌트에서는 가장 먼 점의 길이를 구할 수 있다고 생각하고 풀이하였는데 틀린 이유를 잘 모르겠습니다... 이렇게 풀면 틀린 이유가 있을까요?? 항상 수업 너무 잘 듣고 있습니다. 감사합니다! #include <bits/stdc++.h> using namespace std; int n, m; string a; char mapp[54][54]; bool visited[54][54]; int dis[54][54]; int dy[] = {0,-1,0,1}; int dx[] = {1,0,-1,0}; queue<pair<int,int>> q; queue<pair<int,int>> q2; int max_val = 0; pair<int,int> bfs_1(int y, int x){ visited[y][x]=1; q.push({y,x}); pair<int,int> here; while(q.size()){ here = q.front(); q.pop(); for(int i=0;i<4;i++){ int ny = here.first + dy[i]; int nx = here.second + dx[i]; if(ny<0||nx<0||ny>=n||nx>=m) continue; if(visited[ny][nx]) continue; if(mapp[ny][nx]=='W') continue; visited[ny][nx] = 1; q.push({ny,nx}); } } return here; } int bfs_2(int y, int x){ dis[y][x] = 1; q2.push({y,x}); pair<int,int> here; while(q2.size()){ here = q2.front(); q2.pop(); for(int i=0;i<4;i++){ int ny = here.first + dy[i]; int nx = here.second + dx[i]; if(ny<0||nx<0||ny>=n||nx>=m) continue; if(dis[ny][nx]>0) continue; if(mapp[ny][nx]=='W') continue; dis[ny][nx] = dis[here.first][here.second] + 1; q2.push({ny,nx}); } } return dis[here.first][here.second]; } int main(){ cin >> n >> m; for(int i=0;i<n;i++){ cin >> a; for(int j=0;j<a.length();j++){ mapp[i][j] = a[j]; } } for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ if(mapp[i][j]=='W') continue; if(visited[i][j]) continue; pair<int,int> ret_1 = bfs_1(i,j); int max_dis = bfs_2(ret_1.first, ret_1.second) -1; max_val=max(max_val,max_dis); } } cout << max_val; return 0; }
Kevin의 알기 쉬운 Spring Reactive Web Applications: Reactor 1부
WebFlux의 Non-Blocking의 장점이 "여러 작업에 대해서 단일 스레드로 이벤트 루프 방식으로 Blocking 없이 여러 작업을 번갈아 가며 처리 가능하다" 라고 이해를 했습니다. 강의의 예제도 보았고 또 여러 예제를 만들어 돌려 보아도, 단일 스레드로 여러 subscribe() 요청을 번갈아가면서 처리하는 것을 확인하지를 못하였습니다. 물론 publishOn 이나 subscribeOn, parallel 을 이용 혹은 flatMap 과 delayElements 를 사용하여 별도의 스레드를 띄워 구현한다면 여러 스레드가 병렬로 동시에 여러 요청의 작업을 처리 할 수 있다는 것은 알고 있습니다. 하지만 이 방법은 결국 다수 스레드를 생성하여 각각의 스레드가 각각의 작업을 처리 하는 구조가 되어 Tomcat기반의 동기 MVC 방식에서의 Blocking 멀티스레드와 별반 차이를 체감하지 못하였습니다. 예를 들어 reactor.netty.ioWorkerCount=1 로 설정하고 Rest API "/api/stream" 를 만들어 클라이언트 A가 GET 호출로 구독 시 클라이언트 B는 A가 연결을 끝날때 까지 대기하였습니다. (Blocking MVC와 동일 동작) (기대한 것은 단일 스레드로 클라이언트 A와 B의 요청을 번갈아가며 처리) 또다른 테스트로 main메소드에서 퍼블리셔에 대해 2개의 subscriber가 거의 동시 구독하였을 경우 먼저 시작한 subscriber의 처리가 다 끝나고 그다음 subscriber가 처리 진행하였습니다. (물론 스케줄러 나 delayElements, webclient 등 내부적으로 별도 스레드를 띄우면 병렬 처리 됨) [제가 테스트한 결과 1 - 단일 스레드 순차 수행] [main] WebFluxExample - main - A1 시작 [main] WebFluxExample - main - A2 완료 [main] WebFluxExample - main - A3 완료 [main] WebFluxExample - main - A 체인 최종 결과: A1 -> A2 -> A3 [main] WebFluxExample - main - B1 시작 [main] WebFluxExample - main - B2 완료 [main] WebFluxExample - main - B3 완료 [main] WebFluxExample - main - B 체인 최종 결과: B1 -> B2 -> B3 [제가 테스트한 결과 2 - 멀티 스레드 병렬 수행] [main] DEBUG reactor.util.Loggers - Using Slf4j logging framework [boundedElastic-1] WebFluxExample - boundedElastic-1 - A1 시작 [boundedElastic-2] WebFluxExample - boundedElastic-2 - B1 시작 [boundedElastic-1] WebFluxExample - boundedElastic-1 - A2 완료 [boundedElastic-2] WebFluxExample - boundedElastic-2 - B2 완료 [boundedElastic-1] WebFluxExample - boundedElastic-1 - A3 완료 [boundedElastic-2] WebFluxExample - boundedElastic-2 - B3 완료 [boundedElastic-1] WebFluxExample - boundedElastic-1 - A 체인 최종 결과: A1 -> A2 -> A3 [boundedElastic-2] WebFluxExample - boundedElastic-2 - B 체인 최종 결과: B1 -> B2 -> B3 [원하는 결과 - 단일 스레드 병렬 수행] [동일스레드] WebFluxExample - 동일스레드- A1 시작 [동일스레드] WebFluxExample - 동일스레드- B1 시작 [동일스레드] WebFluxExample - 동일스레드- A2 완료 [동일스레드] WebFluxExample - 동일스레드- B2 완료 [동일스레드] WebFluxExample - 동일스레드- A3 완료 [동일스레드] WebFluxExample - 동일스레드- B3 완료 [동일스레드] WebFluxExample - 동일스레드- A 체인 최종 결과: A1 -> A2 -> A3 [동일스레드] WebFluxExample - 동일스레드- B 체인 최종 결과: B1 -> B2 -> B3 하여 진정한 Webflux의 Non Blocking, 즉 단일 스레드로 (동시 병렬이 아닌) 여러 작업을 번갈아가며 처리하는 것이 가능하다면 처리하는 예제와 결과를 보여주시면 감사하겠습니다.
원본 소스코드를 다운로드 하면 그 안에 각 강의 시간에 배운 코드들이 다 있습니다. 하지만 그 소스들이 다 합쳐져 있는 최종 코드 같은 건 없는 것 같습니다. 예를 들면 main.py 안에는 long_article.py에 배운 글을 길게 작성하는 코드가 빠져 있잖아요. 결국 최종적으로 원고 생성기 프로그램은 배운 것들을 각자 알아서 합쳐서 만들라는 것인가요? 제가 이해한 것이 맞는지 궁금합니다.
강의 이외에, 추가적으로 서버 컴포넌트에 대해 궁금증이 생겨 여러 블로그를 참고 하는 와중, 하나 헷갈리는 개념이 있어 여쭤 보려고 합니다. <알고 싶은 내용> 서버 컴포넌트의 등장 배경 중 "waterfall 문제" 라는 내용이 알맞는 내용인 지 궁금합니다. <과정> 제가 참고했던 여러 블로그에서 공통적으로 언급한 내용 중 하나가 "서버 컴포넌트의 등장 배경 중 하나로 클라이언트 컴포넌트의 waterfall 문제 " 라는 내용이 있었습니다. 그리고, 위의 문제는 서버 컴포넌트 도입 이후, 데이터 요청을 서버에서 사전에 처리하여 해결 되었다고 간단히 설명하고 마치는 내용이었습니다. <제가 헷갈리는 부분> 그렇다면 waterfall 문제는 결국, 서버 컴포넌트 이전의 SSR 방식으로도 해결 수 있는 문제가 아닐까? " 라는 의문이 들었습니다. 이유는 SSR 방식 역시 서버에서 데이터를 미리 가져와 HTML을 생성한 후 클라이언트에 전달하기 때문에, 서버 컴포넌트가 waterfall 문제를 해결했다면 기존 SSR 방식으로도 해결할 수 있지 않을까 하는 생각이 들었습니다. <결과> 위의 내용을 알아보기 위해 아래의 내용을 바탕으로 검색을 해봤지만, 확실한 대답을 찾지 못해 질문을 남겨봅니다. SSR 렌더링 방식에서 waterfall 문제가 발생하는 지의 여부 SSR과 RSC의 차이
강의 너무 잘 들었습니다. 실은, 이전에 다른 강의를 먼저 수강하다가 제대로 끝까지 가지 못했었습니다. 그러다, 이번 강의를 접하고 순식간에 완강했습니다. 정말 실질적으로 필요한 부분을 가르쳐 주고 나머지는 가지치기 해주시는 것 너무 좋습니다. 그리고 원리부터 설명해 주시는 방식도 너무 좋습니다. 이전에는 어디에 쓰이지는지도 알수 없는 너무 지엽적인 부분만 보다가 지쳤었거든요. 다짜고짜 코드만 따라하니 기억에도 하나도 남지 않았습니다. 그래서 다음 강의가 너무너무 기대가 됩니다. 다른, 분이 쓰신 질문에 답을 다신 것을 보니 판다스 강의도 예정하고 있다고 들었는데, 혹시 언제쯤으로 계획하고 계신지 알수 있을까요? 빨리 배워서 실제 업무에 적용해보고 싶습니다.
기본 템플릿 생성 rafce 적용할 때 파일명 기준으로 객체 변수(NavBar) 생성 되는데 오타 때문에 삭제하고 재생성(Navbar)하면 처음 만들었던 이름 그대로 유지되는 습성이 있는데 삭제 하고 다시 만들때 바로 적용 되도록 환경 설정 따로 하는게 있는지 궁금합니다. Components 및 Page 폴더 파일 대소문자 구분 생성 이유가 따로 있는지 아니면 개인적인 개발 습관인지 답변 부탁드립니다.
강의 2분 29초 부분 public class MyBatisConfig { private final ItemMapper itemMapper ; ,,, } 강의에서는 에러가 생기지 않지만, 이 부분에서 itemMapper에 컴파일 에러가 뜹니다. (Could not autowire. No beans of 'ItemMapper' type found.) ItemMapper가 스프링 컨테이너에 스프링 빈으로 등록되지 않아서 생기는 에러가 맞나요? 등록되어있지 않기 때문에 ItemMapper를 주입할 수 없어 컴파일 오류가 나는건지 궁금합니다. 그럼에도 불구하고 메모리db로 하는 테스트와, 서버를 띄워서 하는 테스트 모두 성공하는 이유가 궁금합니다. MyBatisConfig클래스 위에 @MapperScan(basePackages = "hello.itemservice.repository.mybatis") 를 하니 컴파일 에러가 사라지긴 합니다. @MapperScan을 통해 ItemMapper를 Bean으로 수동으로 등록하니 컴파일 오류가 생기지 않는건가요?
안녕하세요! 강의 유익하게 듣고 있는 수강생입니다. 컨테이너 가상화 설명에서 궁금증이 생겨 글 남깁니다. (강의 장면 캡쳐가 불가하여 유사 그림으로 대체합니다!!) 도커는 호스트 OS의 커널을 바로 사용한다는 장점이 있다고 이해했습니다. 이때 여기서 호스트 OS가 리눅스라고 명시되어있는데 mac, windows를 사용하는 일반 사용자들도 호스트 os가 리눅스로 적용되는 것일 까요?? 해당 내용을 찾아보니 도커를 사용할 때는 리눅스 커널이 필수적으로 필요해서 가상화된 Linux를 내부적으로 사용한다고 확인했습니다. 이 내용을 리눅스 환경이 아닌경우 도커 내부에 리눅스가 가상화 기술로 적용되어 있다고 이해하는 것이 맞을까요?? 내장되어 있는 것이 맞다면 컨테이너 별로 리눅스가 별도로 포함되는것인지, 도커위에 하나의 리눅스OS를 갖고 있는 것인지 질문드리고 싶습니다! 유익한 강의 정말 감사드립니다 😀