다음 코드를 보자(주석을 주의깊게 볼 것)

package org.example;
import reactor.core.publisher.Flux;
import reactor.core.scheduler.Schedulers;
public class Main {
	public static void main(String[] args) {
		Flux.just("a", "b", "c", "d")  // 1,2,3,4 네개의 아이템을 순차적으로 방출하는 단일 스트림 생성
			.map(s -> {  // 스레드 분기 없이 호출 스레드에서 해당 스트림 아이템에 대해서 대문자변환 연산수행(아래 .subscribe를 만나기 전까지 지연됨!)
				System.out.println("Map 1 - Thread: " + Thread.currentThread().getName());
				return s.toUpperCase();
			})
			.publishOn(Schedulers.boundedElastic())  //이후 작업은 boundedElastic이라는 사전정의된 별도 스레드에서 하도록 지정함!
			.map(s -> {
				System.out.println("Map 2 - Thread: " + Thread.currentThread().getName());
				return s + "!";
			})
			.subscribe(  // 지연 실행을 시작하는 시점이며, 마지막 스케줄러 지정이 boundedElastic이라 boundedElastic 스레드를 통해 수행됨
				s -> System.out.println("Received " + s + " on Thread: " + Thread.currentThread().getName()));
	}
}

실행결과

> Task :Main.main()
Map 1 - Thread: main
Map 1 - Thread: main
Map 1 - Thread: main
Map 1 - Thread: main
Map 2 - Thread: boundedElastic-1
Received A! on Thread: boundedElastic-1
Map 2 - Thread: boundedElastic-1
Received B! on Thread: boundedElastic-1
Map 2 - Thread: boundedElastic-1
Received C! on Thread: boundedElastic-1
Map 2 - Thread: boundedElastic-1
Received D! on Thread: boundedElastic-1

 

 

예제를 조금 수정한 코드를 보자.

package org.example;
import reactor.core.publisher.Flux;
import reactor.core.scheduler.Schedulers;
public class Main {
	public static void main(String[] args) {
		Flux.just(1, 2, 0, 4)  // 1,2,0,4 네개의 아이템을 순차적으로 방출하는 단일 스트림 생성
			.map(n -> {  // 스레드 분기 없이 호출 스레드에서 해당 스트림 아이템에 대해서 나누기변환 연산수행(아래 .subscribe를 만나기 전까지 지연됨!)
				System.out.println("Map 1 - Thread: " + Thread.currentThread().getName());
				return 10 / n;
			})
			.publishOn(Schedulers.boundedElastic())  //이후 작업은 boundedElastic이라는 사전정의된 별도 스레드에서 하도록 지정함!
			.map(s -> {
				System.out.println("Map 2 - Thread: " + Thread.currentThread().getName());
				return s + "!";
			})
			.doOnNext(s -> {  // 스트림에 영향을 주지 않으면 로깅등 부가작업을 할때 사용
				System.out.println("doOnNext - Thread: " + Thread.currentThread().getName() + " with value: " + s);
			})
			.doOnError(error -> {  // Exception이 발생한 경우만 여기로 떨어진다.
				System.out.println("Error occurred - Thread: " + Thread.currentThread().getName() + " with error: " + error.getMessage());
			})
			.subscribe(  // 지연 실행을 시작하는 시점이며, 마지막 스케줄러 지정이 boundedElastic이라 boundedElastic 스레드를 통해 수행됨
				s -> System.out.println("Received " + s + " on Thread: " + Thread.currentThread().getName()));
		// boundElastic스레드로 중간에 분기되기 때문에 이 출력이 마지막 줄이 아닐 수 있다!
		// 자바에서는 main함수가 종료되더라도 다른 스레드가 강제종료되지 않는다!
		System.out.println("main end");
	}
}

실행결과

> Task :Main.main()
Map 1 - Thread: main
Map 1 - Thread: main
Map 1 - Thread: main
Map 2 - Thread: boundedElastic-1
doOnNext - Thread: boundedElastic-1 with value: 10!
Received 10! on Thread: boundedElastic-1
Map 2 - Thread: boundedElastic-1
doOnNext - Thread: boundedElastic-1 with value: 5!
Received 5! on Thread: boundedElastic-1
main end
Error occurred - Thread: boundedElastic-1 with error: / by zero

이 예시에서는 onDoNext, onDoError, main end시 스레드 종료 개념을 추가적으로 배울 수 있다.

주석을 주의깊에 보면 되기 때문에 따로 설명은 안하겠다.

반응형

'Programming > JAVA' 카테고리의 다른 글

Reactor Context  (0) 2025.05.27
java generic  (0) 2025.05.27
BiFunction, Function을 사용한 함수형 프로그래밍  (0) 2024.01.01
java Optional  (1) 2023.11.04
java enum  (0) 2023.11.03

다음 코드를 보자.

public class SimpleFunctionExample {

    public static void main(String[] args) {
        double powResult = power(2, 3);
        String result = formatResult(powResult);

        System.out.println(result);
    }

    private static double power(int a, int b) {
        return Math.pow(a, b);
    }

    private static String formatResult(double number) {
        return "Result: " + number;
    }
}

실행결과 Result: 8

 

power함수와 formatResult함수를 만들고 farmatResult(power(2,3)) 이렇게 중첩함수를 사용했다.

반면 BiFunction, Function을 사용하면 다음처럼 andThen, apply를 통해 함수형 프로그래밍으로 체이닝을 할 수 있다.

코드출처: https://codechacha.com/ko/java8-bifunction-example/

import java.util.function.BiFunction;
import java.util.function.Function;

public class BiFunctionExample2 {

    public static void main(String[] args) {

        BiFunction<Integer, Integer, Double> func1 = (a1, a2) -> Math.pow(a1, a2);
        Function<Double, String> func2 = (a1) -> "Result: " + a1;

        String result = func1.andThen(func2).apply(2, 3);

        System.out.println(result);
    }
}

실행결과는 동일하다.

 

반응형

'Programming > JAVA' 카테고리의 다른 글

java generic  (0) 2025.05.27
reactor #1  (1) 2024.01.01
java Optional  (1) 2023.11.04
java enum  (0) 2023.11.03
IntelliJ 팁  (0) 2023.11.03

mac에서 brew install python@3.6 등의 명령으로 여러버전의 python을 설치할 수 있으나, 과거 버전은 지원하지 않는다.

이때 pyenv를 통해서 여러버전의 python을 동시에 운용할 수 있다.

먼저 brew install pyenv를 통해서 pyenv를 설치한다음

pyenv install 3.6 등의 명령어를 통해 필요한 버전을 설치하면 된다.

해당 버전으로 전환하기 위해서는 먼저 .zshrc또는 .bashrc파일에 다음 내용을 추가해야한다.

(참고로 macOS의 경우 요즘엔 zsh이 기본이다)

export PATH="$HOME/.pyenv/bin:$PATH"
eval "$(pyenv init --path)"
eval "$(pyenv init -)"

그다음 source ~/.zshrc 또는 source ~/.bashrc로 적용하고

 

pyenv global 3.6 등의 명령어를 통해 버전을 전환하면 된다.

global은 시스템 전체에서 기본적으로 사용할 Python 버전을 설정하라는 명령어이다.

local을 대신 쓰면  그 프로젝트의 디렉터리 내에서만 사용할 Python 버전을 따로 설정할 수 있다.

pyenv versions 를 통해서 현재 시스템에 설치된 버전들을 볼 수도 있다.

pyenv global system을 하면 원래 시스템의 python으로 돌아갈 수도 있다.

 

virtualenv와의 관계

pyenv
역할: pyenv는 여러 버전의 Python을 설치하고 관리하는 데 사용됩니다. pyenv를 사용하면 시스템 전체에 걸쳐 여러 Python 버전을 설치하고, 각각을 필요에 따라 선택하여 사용할 수 있습니다. 이를 통해 서로 다른 프로젝트에서 다른 Python 버전을 쉽게 사용할 수 있습니다.

activate 명령어: pyenv는 환경을 활성화하기 위해 activate 명령어를 직접 사용하지 않습니다. 대신, pyenv local, pyenv global, pyenv shell 같은 명령어를 통해 Python 버전을 설정합니다. 이러한 설정을 통해 특정 디렉터리나 세션에서 사용할 Python 버전을 자동으로 활성화하게 됩니다.

많은 사용자들은 pyenv 를 사용하여 여러 Python 버전을 관리하고,
virtualenv (또는 pyenv 의 플러그인인 pyenv-virtualenv )를 사용하여 특정 버전에 대한 독립적인 개발 환경을 생성합니다. 이렇게 하면 Python 버전 관리와 프로젝트 의존성 관리를 모두 효과적으로 할 수 있습니다.

 

반응형

'Programming > Python' 카테고리의 다른 글

venv  (0) 2023.12.17
mypy / pytype  (1) 2023.10.07
python 한글 스트링 인코딩 핸들링  (0) 2021.11.30
Python GUI Programming(Tkinter)  (1) 2021.01.02
파이선환경 그리고 requirements.txt  (1) 2020.09.20

 

venv는 virtualenv와 비슷하며 특징을 정리하면 다음과 같음

 

venv

  • venv는 python개발진에 의해 개발되었으며, python3.3부터 등장과 동시에 표준라이브러리로 공식 지원됨.
  • 공식 지원되므로 별도의 설치과정이 필요 없음

 

virtualenv

  • virtualenv는 python 2버전 시절 부터 널리 사용되었으며, 따라서 지금도 python2버전을 지원함
  • virtualenv가 표준으로 채택되지 않은 이유는 더 간단하고 일관된 환경을 만들기 위한 판단이었던것으로 보임
  • virtualenv는 venv보다 더 많은 기능을 제공. 예를 들어, 특정 버전의 Python을 지정하여 가상 환경을 생성할 수 있음
  •  Python 표준 라이브러리에 포함되어 있지 않기 때문에 별도로 설치해야 함
반응형

'Programming > Python' 카테고리의 다른 글

pyenv를 통한 python버전 변경  (0) 2023.12.17
mypy / pytype  (1) 2023.10.07
python 한글 스트링 인코딩 핸들링  (0) 2021.11.30
Python GUI Programming(Tkinter)  (1) 2021.01.02
파이선환경 그리고 requirements.txt  (1) 2020.09.20

 

null처리를 하다보면 코드가 지저분해지고, 실수하기가 쉬우며, 실수했을때는 NullPointException이 발생하게 된다. 

java8부터는 이것을 개선하기위해 null이 될 수 있는 객체를 Optional에 넣어서 명시적으로 메소드를 통해 다룰수 있도록 만들었다. 이를 통해 체이닝이 가능해지며 코딩오류 가능성이 줄게 되었다.

(단 람다함수 및 method reference등으로 인해 다소 이해하기 복잡해보일 순 있다)

 

코드예시는 여기 참조

내가 만든 코드 예시는 아래 참조

https://github.com/sevity/problem_solving/blob/main/java/OptionalExample.java

반응형

'Programming > JAVA' 카테고리의 다른 글

reactor #1  (1) 2024.01.01
BiFunction, Function을 사용한 함수형 프로그래밍  (0) 2024.01.01
java enum  (0) 2023.11.03
IntelliJ 팁  (0) 2023.11.03
java공부  (0) 2023.08.12

c++ enum과 다르게 java의 enum은 좀 더 발전된 형태로 상수의 집합이 아닌 타입 자체가 객체이다.

따라서 enum type 마다 속성과 메서드를 가질 수 있으며 생성자로 초기화 한다.

public enum CoffeeSize {
    SMALL(200, 3000),
    MEDIUM(400, 5000),
    LARGE(600, 7000),
    XLARGE(1000, 9000);

    private final int volumeInMl;
    private final long priceInWon;

    CoffeeSize(int volumeInMl, long priceInWon) {
        this.volumeInMl = volumeInMl;
        this.priceInWon = priceInWon;
    }
}

위 예시를 보면 커피 사이즈를 enum으로 SMAL, MEDIUM, LARGE, XLARGE로 나누는데, 각각 볼륨과 가격의 속성을 추가로 가진다.

반응형

'Programming > JAVA' 카테고리의 다른 글

BiFunction, Function을 사용한 함수형 프로그래밍  (0) 2024.01.01
java Optional  (1) 2023.11.04
IntelliJ 팁  (0) 2023.11.03
java공부  (0) 2023.08.12
react/next.js로 만드는 online-judge 사이트 #4 문제관리 프론트엔드  (0) 2023.08.05

 

 

Call Hierachy

Source Insight 처럼 런타임이 아닌데도 콜스택 그래프를 볼 수 있도록 해준다.

오픈소스 분석시 매우 유용하다.

우측 callers of countByProblemId 주목

접근: 메뉴 > 탐색 > 호출계층구조 (Ctrl+Alt+H)

런타임이 아니기 때문에 디버깅시 나오는 콜스택이 외길인데 반해서 콜러가 여러군데로 나오는점이 있으니 분석시 유의.

반응형

브리지 네트워크 (Bridge Network):

Docker에서 기본적으로 제공되는 네트워크 모드입니다.
컨테이너가 독립적인 IP 주소를 가지며, 호스트와는 브리지 네트워크를 통해 통신합니다.

 

bridge는 Docker의 기본 네트워크 드라이버 중 하나입니다. Docker가 설치되면 기본적으로 생성되는 네트워크 모드로, 개별 컨테이너들이 독립된 네트워크 네임스페이스에서 동작하게 합니다. 이렇게 하면 컨테이너 간의 네트워크 통신이 보안적으로 격리됩니다.

bridge 네트워크에 대한 주요 특징은 다음과 같습니다:

  • 격리: 각 컨테이너는 독립된 네트워크 네임스페이스를 가지기 때문에 서로 격리됩니다.
  • 자동 IP 할당: Docker의 내장 DHCP 서버에 의해 자동으로 IP 주소가 할당됩니다. 보통 172.17.0.x 범위의 주소가 기본으로 사용됩니다.
  • 포트 매핑: 호스트 시스템의 특정 포트를 컨테이너의 특정 포트에 매핑(포워딩)할 수 있습니다. 예를 들어, 호스트의 8080 포트를 컨테이너의 80 포트에 매핑할 수 있습니다.
  • 컨테이너 간 통신: 같은 bridge 네트워크에 있는 컨테이너끼리는 IP 주소를 통해 서로 통신할 수 있습니다.

그러나 bridge 네트워크 모드에는 몇 가지 제한사항도 있습니다

  • 외부 네트워크와의 통신은 NAT(Network Address Translation)를 통해 이루어지기 때문에 성능 오버헤드가 있을 수 있습니다.
  • 호스트와 컨테이너 간의 통신을 위해서는 포트 매핑이 필요합니다.
  • 다른 호스트에 있는 컨테이너와의 통신은 기본적으로 지원되지 않습니다.
  • 이러한 제한사항 때문에 복잡한 배포나 여러 호스트 간의 통신이 필요한 경우에는 overlay, macvlan 등의 다른 네트워크 드라이버를 사용하기도 합니다.

 

호스트 네트워크 (Host Network):

컨테이너가 호스트의 네트워크 네임스페이스를 사용합니다.
컨테이너는 호스트의 IP 주소와 포트를 직접 사용할 수 있습니다.

반응형

'Programming > Linux' 카테고리의 다른 글

docker-compose  (0) 2023.10.28
Nginx  (1) 2023.08.16
Redis  (0) 2023.08.10
kafka  (0) 2023.07.31
ELK연습  (0) 2023.07.30

여러 도커간의 디펜던시를 설정해서 빌드하고 띄우는 일을 할 수 있다.

 

용어

서비스 (Service)

Docker Compose 내에서 쓰이는 개념으로, 도커 컨테이너의 구성 및 실행 방법을 정의한 것.
서비스는 하나의 컨테이너일 수도 있고, 동일한 이미지를 기반으로 하는 여러 컨테이너의 집합일 수도 있다.

예를 들어, docker-compose.yml 파일에 다음과 같은 정의가 있다면:

services:
  web:
    image: nginx:latest
    ports:
      - "80:80"
  database:
    image: mysql:5.7
    environment:
      - MYSQL_ROOT_PASSWORD=my-password

여기에서 web과 database는 각각 하나의 서비스.
이 경우, 각 서비스는 각각 하나의 컨테이너를 생성하지만, 필요에 따라 한 서비스에서 여러 컨테이너를 생성할 수도 있습니다 (예: 스케일링 목적으로).


결국, "서비스"는 Docker Compose에서 응용 프로그램의 한 부분 (예: 웹 서버, 데이터베이스)을 나타내며, 이 서비스를 구성하는 데 필요한 설정과 함께 도커 이미지 정보를 포함합니다.

 

사용방법

docker-compose build:

이 명령어는 docker-compose.yml 파일에 정의된 모든 서비스의 이미지를 빌드합니다.
docker-compose.yml 파일에서 build: 섹션을 사용하여 Dockerfile의 위치나 빌드 컨텍스트 등을 지정한 서비스에 대해서만 이 명령어를 사용해야 합니다.


docker-compose up -d:

위에서 빌드한 이미지들의 실행 인스턴스인 컨테이너들을 만들어 실행
-d 옵션은 "detached mode"를 의미하며, 백그라운드에서 컨테이너를 실행하라는 것을 의미
이미지가 없다면 빌드도 시도하기 때문에 docker-compose build 없이 이것만 실행해도 되긴 하나,

코드 변경시 재빌드해주진 않기 때문에 코드 변경이 있었다면 build후 up해야 한다.

 

docker-compose down -v:

up과 반대로 컨테이너들 중단하고 없애준다.

-v하면 관련 데이터 볼륨도 제거해준다.

여기서 데이터 볼륨(Data Volume)은 Docker 컨테이너 파일 시스템의 일부를 호스트 시스템에 저장하는데 사용되는 매커니즘으로, 컨테이너간 데이터를 공유하는 공유폴더 개념으로 쓰이거나 데이터를 영구적으로 저장할수 있게 해준다.

그 예시로는 (DB, 로그, config file등이 있다)

 

 

docker-compose ps

docker-compose로 관리되는 컨테이너들의 현재 상태와 관련된 정보를 조회

 

다음내용 확인가능

  • 서비스 상태 확인: docker-compose up 명령을 사용하여 여러 서비스를 시작한 후, 각 서비스의 컨테이너가 올바르게 실행 중인지, 혹은 중지된 상태인지를 확인하기 위해 사용됩니다.
  • 문제 진단: 서비스에 문제가 발생했을 때, 어떤 컨테이너가 문제를 일으키고 있는지 확인하기 위해 사용될 수 있습니다. 예를 들어, 컨테이너가 계속 재시작되는 경우, docker-compose ps를 통해 해당 컨테이너의 상태를 확인할 수 있습니다.
  • 포트 정보 확인: 각 컨테이너에서 어떤 포트가 호스트와 연결되었는지 확인하려 할 때 사용됩니다.
  • 스케일링 확인: docker-compose up --scale 명령을 사용하여 서비스의 인스턴스 수를 조정한 경우, 현재 실행 중인 인스턴스 수를 확인하기 위해 사용됩니다.
  • 컨테이너 이름 확인: docker-compose로 시작된 컨테이너들은 특정한 네이밍 규칙을 가지고 있습니다. 이 이름을 확인하기 위해 docker-compose ps를 사용할 수 있습니다.

아래는 예시

               Name                             Command               State                                  Ports
--------------------------------------------------------------------------------------------------------------------------------------------------
table-walkthrough_data-generator_1   /docker-entrypoint.sh            Up
table-walkthrough_grafana_1          /run.sh                          Up      0.0.0.0:3000->3000/tcp,:::3000->3000/tcp
table-walkthrough_jobmanager_1       /docker-entrypoint.sh stan ...   Up      6123/tcp, 0.0.0.0:8082->8081/tcp,:::8082->8081/tcp
table-walkthrough_kafka_1            start-kafka.sh                   Up      0.0.0.0:9092->9092/tcp,:::9092->9092/tcp
table-walkthrough_mysql_1            docker-entrypoint.sh --def ...   Up      3306/tcp, 33060/tcp
table-walkthrough_taskmanager_1      /docker-entrypoint.sh task ...   Up      6121/tcp, 6122/tcp, 6123/tcp, 8081/tcp
table-walkthrough_zookeeper_1        /bin/sh -c /usr/sbin/sshd  ...   Up      0.0.0.0:2181->2181/tcp,:::2181->2181/tcp, 22/tcp, 2888/tcp, 3888/tcp
sevity@sevityubuntu:~/workspace/flink-playgrounds/table-walkthrough$
반응형

'Programming > Linux' 카테고리의 다른 글

docker network  (0) 2023.10.29
Nginx  (1) 2023.08.16
Redis  (0) 2023.08.10
kafka  (0) 2023.07.31
ELK연습  (0) 2023.07.30

branch생성시점의 master가 너무 오래돼서, 최신 master의 branch로 업데이트 하고 싶을때

방법1. merge

방법2. rebase

 

타인이 올린 PR의 Files changed를 터미널에서 확인하기

현재 master의 최신이 아닌 PR을 올린사람이 작업을 시작할때의 master가 기준이 됨에 유의

git fetch origin
git diff $(git merge-base origin/master origin/pr-branch-name)..origin/pr-branch-name

 

 

 

타인이 올린 PR을 내 로컬로 가져와서 검토하기

 

예를들어 위와 같은 PR이 올라왔다고 하자.

git fetch origin pull/51/head:bump-twisted 라고 치면 로컬에 "bump-twisted"라고 하는 브랜치가 생성된다(이것은 임의로 지정한 이름이며 생략하면 "pull/51/head"가 된다)

git branch를 해보면 아래처럼 bump-twisted라는 브랜치가 로컬 저장소에 추가된 것을 볼 수 있다.

$ git branch
* master
  bump-twisted

아직은 master를 바라보고 있어 PR의 내용이 로컬저장소에 반영되지 않았다.

git checkout bump-twisted 라고 치면 반영된다.

만약 PR을 올린사람이 merge전에 PR의 내용을 변경했다면

git pull origin pull/51/head:bump-twisted 다시 이렇게 치면 된다. 

 

위 방법대신

git branch -r을 해보면 다음처럼 이미 해당 PR들의 branch 들이 생성되어 있는 것을 볼 수 있는데,

(coin) sevity@raspberrypi:~/workspace/temp/coin_strategy $ git branch -r
  origin/HEAD -> origin/master
  origin/dependabot/pip/tornado-6.3.3
  origin/dependabot/pip/twisted-23.8.0
  origin/dependabot/pip/urllib3-1.26.18
  origin/master

여기서 해당 PR을 확인하고 git pull origin dependabot/pip/twisted-23.8.0:bump-twisted 이렇게 하는 방법도 있다.

 

 

반응형

'Programming > Git' 카테고리의 다른 글

git 초기설정  (1) 2023.06.06
git log  (0) 2019.12.09
git 자주 쓰는 명령어 모음  (0) 2019.09.27
git branch 관련  (0) 2019.04.17
github  (0) 2018.11.07

+ Recent posts