update: 2024.3.9

항목에 대한 정보

  1. Model: 모델의 이름 또는 식별자입니다.
  2. Params: 모델의 매개변수 수 (일반적으로 모델의 크기를 나타냅니다).
  3. HumanEval: 모델의 인간 평가 점수입니다. 이는 모델이 사람의 품질에 얼마나 근접한지를 나타냅니다.
  4. MBPP: Mean Binary Perplexity (MBPP)는 모델이 이진 데이터의 평균 퍼플렉서티를 나타냅니다. 이것은 모델이 이진 데이터를 얼마나 잘 예측하는지를 측정합니다.
  5. HF: Hugging Face 모델 허브(Hugging Face Model Hub)의 해당 모델에 대한 링크입니다.
  6. Source: 해당 모델에 대한 추가 정보를 찾을 수 있는 링크입니다.
Model Params HumanEval MBPP HF Source
GPT-4 + Reflexion ? 91.0 77.1 paper
GPT-4 (latest) ? 84.1 80.0 github
DeepSeek-Coder-Instruct 33B 79.3 70.0 ckpt github
DeepSeek-Coder-Instruct 7B 78.6 65.4 ckpt github
GPT-3.5-Turbo (latest) ? 76.2 70.8 github
Code-Llama 34B 62.2 61.2 paper
Pangu-Coder2 15B 61.6 paper
WizardCoder-15B 15B 57.3 51.8 ckpt paper
Code-Davinci-002 ? 47.0 paper
StarCoder-15B (Prompted) 15B 40.8 49.5 ckpt paper
PaLM 2-S ? 37.6 50.0 paper
PaLM-Coder-540B 540B 36.0 47.0 paper
InstructCodeT5+ 16B 35.0 paper
StarCoder-15B 15B 33.6 52.7 ckpt paper
Code-Cushman-001 ? 33.5 45.9 paper
CodeT5+ 16B 30.9 paper
LLaMA2-70B 70B 29.9 ckpt paper
CodeGen-16B-Mono 16B 29.3 35.3 paper
PaLM-540B 540B 26.2 36.8 paper
LLaMA-65B 65B 23.7 37.7 paper
CodeGeeX 13B 22.9 24.4 paper
LLaMA-33B 33B 21.7 30.2 paper
CodeGen-16B-Multi 16B 18.3 20.9 paper
AlphaCode 1.1B 17.1 paper
반응형

'개발' 카테고리의 다른 글

Mac이 AI PC로서 최고인 이유  (0) 2024.02.03
2024년 프로그래밍 랭킹  (1) 2024.01.02
gitlab 설치(apache --proxy--> gitlab)  (0) 2023.12.27
elixir vs rust 비교  (1) 2023.12.27
vscode dev containers  (1) 2023.12.22

오늘은 Mac이 AI PC로서 왜 최고인지에 대해 이야기해보려고 합니다. 여러분도 알다시피, 인공지능은 우리 삶의 많은 부분을 변화시키고 있죠. 그리고 이러한 변화를 이끌어가는 데 있어서 Mac 컴퓨터가 중요한 역할을 하고 있습니다.

강력한 뉴럴 엔진

Mac 컴퓨터는 매년 더 발전하는 신경망 엔진(Neural Engine)을 갖추고 있어서, 강력한 AI PC로 사용할 수 있습니다. Apple의 M3 칩 가족은 세 년 전 M1 칩과 비교하여 60% 더 빠른 신경망 엔진을 갖추고 있으며, 이전의 M2 칩과 비교하면 15% 더 빠릅니다.

메모리 관리

AI 작업에는 많은 메모리(RAM)와 그래픽 메모리(VRAM)가 필요합니다. Mac 컴퓨터는 이러한 작업에 대한 메모리 관리를 뛰어나게 잘 합니다. Apple Silicon Mac은 중앙 처리 장치(CPU)와 그래픽 처리 장치(GPU) 코어 간에 공유되는 단일 메모리를 사용하지만, Windows PC보다 메모리 관리가 더 좋습니다.

서드파티 AI 앱 지원

Mac은 다양한 온라인 AI 도구를 실행할 수 있습니다. 예를 들어, LM Studio를 Mac에서 사용하여 주요 언어 모델(LLM)을 실행할 수 있습니다. Llama 2도 다양한 방법으로 로컬로 실행될 수 있습니다. 오디오와 동영상 AI 소프트웨어 앱, 같은 Stable Diffusion과 Whisper도 Mac에서 원활하게 작동합니다.

사용자 기반

Mac은 이미 AI PC로 사용되고 있습니다. 2020년부터 Mac은 신경망 엔진을 탑재하여 AI PC로 사용할 수 있습니다. 이는 2020년 출시된 엔트리 레벨 Mac Mini와 MacBook Air가 4년된 지금도 AI PC로 사용할 수 있다는 것을 의미합니다.

Mac은 사용자가 구매해야 할 새로운 AI PC를 구매하지 않고도 AI를 사용할 수 있는 장점이 있습니다. 새로운 노트북이나 PC를 구매하는 빈도가 높지 않기 때문에, 평균 Windows 사용자는 몇 년 동안 NPU를 탑재한 시스템을 구매할 것입니다. 그러나 Mac을 보면, 수백만 명의 사람들이 이미 AI PC로 사용할 수 있는 Mac을 가지고 있습니다.

반응형

'개발' 카테고리의 다른 글

코딩 AI 랭킹  (0) 2024.03.09
2024년 프로그래밍 랭킹  (1) 2024.01.02
gitlab 설치(apache --proxy--> gitlab)  (0) 2023.12.27
elixir vs rust 비교  (1) 2023.12.27
vscode dev containers  (1) 2023.12.22

아래는 개인적인 의견이며, 실제 다수의 개발 환경과는 차이가 있을 수 있습니다.

Python

  • 사용범위: 데이터 과학, 웹 개발, 인공지능, 자동화 스크립트
  • 특징: 초보자에게 친숙하고 다양한 라이브러리를 제공
  • 선정 이유: AI와 빅데이터 분야의 성장으로 인해 지속적으로 수요가 증가

파이썬은 함수형 프로그래밍부터 객체 지향 프로그래밍까지 다양한 스타일을 수용하는 다목적 프로그래밍 언어로 주목받고 있습니다YouTube, Google 검색, iRobot 머신과 같은 유명한 플랫폼은 Python의 견고함 덕분에 존재할 수 있었습니다

HackerRank의 데이터에 따르면 Python은 미주 지역 채용 관리자가 두 번째로 많이 찾는 언어입니다사용자 친화적인 특성 덕분에 초보자와 숙련된 개발자 모두에게 인기가 높습니다

Python의 풍부한 라이브러리는 미리 빌드된 명령어로 작업을 간소화하며, 대화형 특성은 실시간 코드 테스트에 도움이 됩니다채용 관리자의 50% 이상이 파이썬 기술을 우선시하는 등 광범위한 수요를 고려할 때, 파이썬은 프로그래밍 환경의 주요 자산으로 남아 있습니다.

JavaScript

  • 사용범위: 웹 프론트엔드, 백엔드(Node.js), 모바일 애플리케이션(React Native)
  • 특징: 웹 표준 기술로서의 지위와 비동기 처리에 강점
  • 선정 이유: 웹 개발의 필수 언어로서의 지속적인 인기

스택 오버플로의 2020년 개발자 설문조사에 따르면 자바스크립트는 전 세계에서 가장 많이 사용되는 언어로 69.7%로 1위를 차지했습니다이러한 우위는 미주 지역의 채용 관리자들 사이에서 자바스크립트에 대한 높은 수요를 통해 더욱 두드러집니다

자바스크립트는 개발자가 애니메이션 그래픽, 인터랙티브 맵 등과 같은 동적 요소를 제작할 수 있도록 웹 페이지의 상호작용성을 향상시키는 데 중추적인 역할을 합니다HTML 및 CSS와 결합된 자바스크립트는 향상된 웹사이트 제어 기능을 제공하여 뛰어난 사용자 탐색 및 가독성을 보장합니다자바스크립트가 널리 사용되는 이유는 대부분의 웹 브라우저와 통합되고 초보자도 쉽게 사용할 수 있기 때문입니다방대한 온라인 커뮤니티와 광범위한 지원 리소스는 자바스크립트의 최상위 프로그래밍 언어로서의 입지를 더욱 공고히 해줍니다.

Java

  • 사용범위: 엔터프라이즈급 백엔드 시스템, 안드로이드 앱 개발

  • 특징: 강력한 크로스 플랫폼 지원과 안정적인 성능

  • 선정 이유: 대규모 시스템 개발과 안드로이드 시장의 확대

    Java는 어디서나 한 번만 작성하면 실행할 수 있다는 철학으로 엔터프라이즈급 애플리케이션과 안드로이드 앱 개발에서 확고한 입지를 다지고 있습니다강력한 커뮤니티 지원과 이식성 덕분에 지속적인 인기를 누리고 있습니다

C#

  • 사용범위: 윈도우 애플리케이션, 게임 개발(Unity), 웹 개발(ASP.NET)

  • 특징: 강력한 개발 환경과 통합된 개발 경험

  • 선정 이유: 게임 개발과 .NET 생태계의 확장

    C++는 시스템 프로그래밍, 게임 개발, 고성능 애플리케이션의 초석이 되고 있습니다높은 수준의 추상화를 통해 낮은 수준의 조작이 가능하므로 성능이 중요한 작업에 적합합니다

    TypeScript

  • 사용범위: 대규모 웹 애플리케이션 개발

  • 특징: JavaScript의 상위 집합으로 타입 안정성 제공

  • 선정 이유: JavaScript의 복잡성 관리와 안정적인 개발을 위한 수요 증가

    자바스크립트의 상위 집합인 타입스크립트는 정적 타이핑을 추가하여 대규모 애플리케이션에 선호되는 선택지입니다기존 JavaScript 코드베이스와의 호환성 및 향상된 개발자 경험으로 인해 그 중요성이 날로 높아지고 있습니다

Swift

  • 사용범위: iOS 및 macOS 애플리케이션 개발

  • 특징: Apple 플랫폼에 최적화된 성능과 간결한 문법

  • 선정 이유: Apple 생태계 내 앱 개발의 필수 언어

    Apple의 프로그래밍 언어인 Swift는 iOS 및 macOS 앱 개발에 필수적인 언어입니다구문이 간결하고 표현력이 뛰어나 개발자들이 원활하고 직관적인 사용자 환경을 만들기 위해 선호하는 언어입니다

Kotlin

  • 사용범위: 안드로이드 앱 개발, 서버 사이드 애플리케이션

  • 특징: 간결하고 표현력 있는 문법, 자바와의 상호 운용성

  • 선정 이유: 안드로이드 공식 개발 언어로의 지정과 개발자 커뮤니티의 성장

    Google이 Android 개발을 위해 승인한 Kotlin은 간결함과 Java와의 상호 운용성으로 인기를 얻고 있습니다Kotlin을 배우면 효율적이고 현대적인 Android 애플리케이션을 만들 수 있는 길이 열립니다

Go (Golang)

  • 사용범위: 시스템 프로그래밍, 분산 시스템, 클라우드 서비스
  • 특징: 간결한 문법과 빠른 실행 속도, 병행성(concurrency) 지원
  • 선정 이유: 클라우드 기반 서비스와 마이크로서비스 아키텍처의 인기

Rust

  • 사용범위: 시스템 프로그래밍, 웹 어셈블리, 임베디드 시스템
  • 특징: 메모리 안전성과 병행성을 보장하는 현대적인 시스템 언어
  • 선정 이유: 안전한 시스템 개발에 대한 수요 증가

Rust는 스택 오버플로와 같은 플랫폼에서 꾸준히 호평을 받고 있으며, 종종 가장 선호도가 높은 상위 프로그래밍 언어 중 하나로 꼽히기도 합니다사용자의 86%에 달하는 상당수가 Rust에 대한 전문성을 강화하는 데 큰 관심을 표명하고 있습니다그러나 이러한 매력에도 불구하고 설문조사에 참여한 개발자 중 단 3%만이 Rust를 사용한다고 답해, 광범위한 프로그래밍 커뮤니티에서 틈새 시장으로 인식되고 있음을 알 수 있습니다

Rust는 구문은 C++와 비슷하지만 응용 가능성이 더 넓은 '다중 패러다임' 언어로 구분됩니다신속한 컴파일, 향상된 크로스 플랫폼 기능 또는 더 밝은 커리어의 길을 우선시하든, Rust를 채택하는 것은 전략적인 선택이 될 수 있습니다.

SQL

  • 데이터베이스 관리
    • 영업 보고서
    • 비즈니스 관리

일반적으로 구조화된 쿼리 언어로 알려진 SQL은 프로그래머가 데이터베이스와 상호 작용할 수 있는 특수 도구로 사용됩니다특히 관계형 데이터베이스 관리 시스템(RDBMS)에 맞게 설계된 SQL은 데이터 검색, 레코드 업데이트, 추가 및 삭제와 같은 작업에 탁월합니다

SQL의 기능은 칭찬할 만하지만, SQL은 소규모 데이터베이스에서 가장 효율적이며 더 크고 복잡한 데이터베이스에서는 한계에 직면할 수 있다는 점에 유의할 필요가 있습니다그럼에도 불구하고 SQL은 프로그래밍 분야에서 세 번째로 많이 사용되는 언어이며, 개발자의 54.7%가 SQL의 기능을 활용하고 있을 정도로 널리 사용되고 있다는 사실은 부인할 수 없습니다.

NOSQL

  • 데이터베이스 관리
  • 영업 보고서
  • 비즈니스 관리

비관계형 SQL의 약자인 NoSQL은 사용자 친화적인 특성을 유지하면서 SQL의 확장성을 향상시키는 것을 목표로 하는 솔루션으로 등장했습니다SQL은 조작과 검색을 위해 데이터를 테이블로 구성하는 관계형 데이터베이스 시스템에 의존하지만, NoSQL은 이러한 테이블 구조를 따르지 않는다는 점에서 차별화됩니다

이러한 유연성 덕분에 NoSQL은 계층적 네트워크 데이터 저장이나 광범위한 클라우드 기반 애플리케이션 지원과 같은 작업에 특히 능숙합니다이러한 적응성을 고려할 때 SQL과 NoSQL은 모두 가장 인기 있는 프로그래밍 언어 중 하나입니다.

반응형

'개발' 카테고리의 다른 글

코딩 AI 랭킹  (0) 2024.03.09
Mac이 AI PC로서 최고인 이유  (0) 2024.02.03
gitlab 설치(apache --proxy--> gitlab)  (0) 2023.12.27
elixir vs rust 비교  (1) 2023.12.27
vscode dev containers  (1) 2023.12.22

ReserveProxy 를 이용해서 gitlab을 운영하면, gitalb site 안에 있는 링크가 깨지는 경우가 있습니다. 이를 해결하기 위해서는 아래 파일에 dns domain 주소로 변경하면 됩니다.

아래와 같이 시스템이 구성이 되어 있는 상태입니다.

flowchart TD
apache(gitlab.xxxxxx.com) --proxy--> gitlab(10.2.2.2:8000)

설정

apache 설정

<VirtualHost *:443>
    ServerName gitlab.xxxxxxxx.com

    ProxyRequests Off       # Reserve Proxy Mode
    ProxyPreserveHost On
    <Proxy *>
        Order deny,allow
        Allow from all
    </Proxy>

    ProxyPass / https://192.168.20.100/ nocanon
    ProxyPassReverse / https://192.168.20.100/

    <Location />
        Order Deny,Allow
        Deny from all
        Allow from 162.21
    </Location>

    AllowEncodedSlashes NoDecode
    ErrorLog logs/gitlab_error_log
    TransferLog logs/gitlab_access_log
    LogLevel warn

    SSLEngine on
    SSLProxyEngine On

    SSLCertificateFile "/etc/pki/tls/certs/xxxxxxxxxx.com.crt"
    SSLCertificateKeyFile "/etc/pki/tls/private/xxxxxxxxxx.com.key"
    SSLCertificateChainFile "/etc/pki/tls/RootChain/chain_all_ssl.crt"
    SSLCACertificateFile "/etc/pki/tls/RootChain/chain_ssl.crt"


    CustomLog "/etc/httpd/logs/gitlab_" \
              "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
</VirtualHost>

도메인주소로 proxy 해서 사용해서 사용할 것이라 ProxyPass 부분을 https 로 설정해 주었습니다.
필수옵션:

  1. nocanon
  2. AllowEncodedSlashesgitlab.rb 설정
external_url 'https://gitlab.domain.net
puma['enable'] = true
puma['ha'] = false
puma['worker_timeout'] = 60
puma['worker_processes'] = 2
puma['min_threads'] = 1
puma['max_threads'] = 4
puma['listen'] = '127.0.0.1'
puma['port'] = 8001
puma['socket'] = '/var/opt/gitlab/gitlab-rails/sockets/gitlab.socket'
puma['somaxconn'] = 1024
puma['pidfile'] = '/opt/gitlab/var/puma/puma.pid'
puma['state_path'] = '/opt/gitlab/var/puma/puma.state'
puma['log_directory'] = "/var/log/gitlab/puma"
puma['exporter_enabled'] = false
puma['exporter_address'] = "127.0.0.1"
puma['exporter_port'] = 8083
letsencrypt['enable'] = false
  • external_url 에 domain 주소로 설정을 하면 letencrypt 기능이 자동으로 동작하는 것 같다. 그래서, 옵션으로 letsencrypt 부분을 false 처리 해 주었습니다.

Optional

위에 설정으로 gitlab 에 접속을 할 수 없을 경우에 아래와 같은 옵션을 사용할 수 있습니다.

1. /opt/gitlab/embedded/service/gitlab-rails/config/gitlab.yml 에 있는 정보를 변경

nginx --> gitlab 으로 proxy로 연결해서 사용하게 되면, 링크가 깨지는 현상이 발생한다. 이를 해결하기 위해서 아래와 같은 설정으로 임시 해결할 수 있다. 단, 다른 기능이 또 안될 수 있다. (이 부분은 아직 해결을 못하고 있다.) 예를 들어 gitlab-runner 에 대한 설정을 하려고 들어가는 화면에서 링크가 깨진다.

production: base
  #
  # 1. GitLab app settings
  # ==========================

  ## GitLab settings
  gitlab:
    ## Web server settings (note: host is the FQDN, do not include http://)
    host: gitlab.xxxxxxxxxxxxx.com
    port: 443
    https: false

2. gitlab restart

gitlab-ctl restart
반응형

'개발' 카테고리의 다른 글

Mac이 AI PC로서 최고인 이유  (0) 2024.02.03
2024년 프로그래밍 랭킹  (1) 2024.01.02
elixir vs rust 비교  (1) 2023.12.27
vscode dev containers  (1) 2023.12.22
svn to git 마이그레이션 (맥)  (0) 2023.12.13

개인적으로 새로운 언어를 공부하는 것은 너무나 재미있습니다. 새로운 대륙을 향해 돛단배를 몰고가는 것과 같습니다. 어디로 갈지 모르지만, 미지의 세계를 목표로 출발하는 마음은 셀렘이라는 감정일 것입이다.

이 글에서는 두 가지 언어의 기능, 장단점, 코드 예제를 통해 이 두 가지 언어를 비교해 보겠습니다. 이 글을 읽고 나면 어떤 프로그래밍 언어가 여러분의 필요에 맞는지 더 잘 알 수 있기를 바랍니다.

엘릭서

Elixir는 Erlang VM에서 실행되는 함수형 프로그래밍 언어입니다. Ruby와 동일한 스크립팅 스타일을 사용하지만, Ruby는 객체 지향 언어 패러다임을 따르고 Elixir는 함수형 패러다임을 따른다는 차이점이 있습니다.

특징

  • Elixir는 처음부터 동시성을 가장 잘 처리하는 데 중점을 두었습니다.
  • Elixir는 함수형 프로그래밍 패러다임을 따르기 때문에 반복적인 코드 없이 쉽게 작성할 수 있는 언어를 만들기 위해 노력합니다.
  • Elixir는 내결함성(결함 감내 시스템: Fault tolerant system)을 갖도록 설계되어 문제가 발생했을 때 재시작할 수 있습니다.
  • Elixir는 확장성이 뛰어납니다. 예를 들어, GPU에서 실행할 수 있습니다.
  • 대화형 또는 컴파일된 형태로 Repl에서 Elixir를 실행할 수 있습니다.

Elixir는 확장 가능하고 내결함성 있는 애플리케이션을 구축하는 데 적합한 강력하고 다재다능한 프로그래밍 언어입니다. 함수형 프로그래밍 패러다임, 동시성 기능, Erlang 에코시스템과의 호환성 덕분에 다양한 도메인 및 산업에서 널리 사용되고 있습니다.

엘릭서를 사용하는 곳

Elixir는 Pinterest, Bleacher Report, Discord를 비롯한 다양한 기업과 조직에서 사용하고 있습니다. 대량의 트래픽을 처리할 수 있고 내결함성이 뛰어나 웹 애플리케이션과 분산 시스템을 구축하는 데 널리 사용됩니다.

문서에 따르면 주목할 만한 Elixir 사용자는 다음과 같습니다.

  1. 펩시코: PepsiCo는 소비재 판매를 위한 전자상거래 도구로 Elixir를 사용한다고 보고했습니다. 이들은 Elixir가 강력하고, 간단하며, 배우기 쉽고, 효율적이라는 점을 발견했습니다. Elixir를 사용한 펩시코 지점은 2019년에 20억 달러의 수익을 올렸습니다.
  2. Spotify: Spotify는 백엔드 개발에 Elixir를 사용합니다. 방대한 데이터베이스와 수많은 활성 사용자로 인해 초당 수천 건의 요청을 처리하고 처리할 수 있는 기술이 필요했습니다. Elixir는 필요한 수준의 동시성을 제공하여 세계적인 음악 및 엔터테인먼트 플랫폼으로 성장하는 데 도움을 주었습니다.
  3. Discord: 게이머를 위한 채팅 플랫폼인 Discord 역시 Elixir를 사용하고 있습니다. 대용량 데이터와 엄청난 트래픽을 처리할 수 있는 기술이 필요했습니다. Elixir를 통해 수백만 명의 사용자도 실시간으로 처리할 수 있었습니다. Elixir는 기술 스택의 주요 언어가 되었습니다.
  4. WhatsApp: 전 세계에서 가장 인기 있는 메시징 앱 중 하나인 WhatsApp은 Elixir를 사용합니다. 이 애플리케이션은 처음에 Erlang으로 완전히 작성된 후 Elixir 기반 요소를 도입하여 개선되었습니다. Elixir는 WhatsApp이 방대한 트래픽과 대량의 요청을 처리하는 데 도움이 됩니다.
  5. Heroku: Elixir와 Phoenix 프레임워크를 사용하여 대시보드를 구동하는 Heroku

Elixir 장단점

Elixir의 장점

  • 내결함성(결함 감내 시스템: Fault tolerant system): 동시성을 사용하면 시스템은 종종 많은 문제에 직면합니다. 이러한 문제 중 하나는 하드웨어 오류, 소프트웨어 버그, 네트워크 문제 또는 리소스 제약으로 인해 시스템의 일부가 다운될 수 있다는 것입니다. Elixir는 시스템의 안정성과 장애에 대한 복원력을 보장하는 데 탁월합니다.
  • 확장성(Scalability): Elixir는 동시성 시스템 개발에 항상 우선순위를 두어온 Erlang VM(BEAM)에서 실행되므로 확장성이 뛰어납니다. 이 언어는 서로 통신하는 경량의 격리된 스레드에서 실행됩니다. 또한 Elixir를 사용하여 여러 머신에서 프로세스를 실행하고 통신할 수 있으므로 수평적 확장성을 달성할 수 있습니다.
  1. 웹 API
  2. 강력하고 동적으로(런타임에 확인) 입력됩니다.
  3. 소프트 실시간 서비스는 챗봇이나 Google 문서와 같은 소켓 연결로 구축할 수 있습니다. 하드 실시간 서비스에는 적합하지 않습니다(두 서비스의 차이점은 여기에 있습니다).
  4. 높은 확장성과 내결함성 지원을 제공합니다.
  5. 동시성은 액터 모델을 기반으로 합니다. 이는 Agha의 클래식 액터 모델과 대체로 유사합니다. 이러한 유형의 액터 모델을 프로세스 기반 액터라고 합니다. 이는 시작부터 완료까지 실행되는 계산으로 정의됩니다. 대신 Agha의 클래식 액터 모델은 액터를 거의 행동의 상태 머신과 그 사이를 전환하는 로직으로 정의합니다. 프로세스 기반 액터 모델은 에릭슨에서 Erlang을 개발하면서 처음에 개발되었습니다.
  6. 또한 패턴 매칭을 지원하므로 더 복잡한 데이터 유형을 분해하는 데 도움이 될 수 있습니다.
  7. 안정적인 라이브러리와 지원 커뮤니티가 있지만 Nodejs나 Python과 같지는 않지만 충분히 괜찮은 수준입니다(인기 있는 커뮤니티는 거의 없음).
  8. 개발자 경험이 좋습니다.

Elixir의 단점

  • 소규모 커뮤니티: Elixir 프로젝트에서 문제가 발생하면 커뮤니티가 상대적으로 작기 때문에 해결책을 찾거나 질문에 대한 답을 찾기가 어려울 수 있습니다.
  • 구직 시장에서 낮은 수요: 향후에는 달라질 수 있지만, 개발자 커뮤니티의 많은 부분에서 숙련된 Elixir 개발자에 대한 수요가 적기 때문에 구직 시장에서 이들을 찾기가 어려울 수 있습니다.

    Exlixir의 코드

Elixir의 코드는 스레드보다 가볍고 저렴한 프로세스를 통해 실행되므로 수천 개 또는 수백만 개의 프로세스를 생성할 수 있습니다. Elixir에서 프로세스는 격리되어 메모리를 공유하지 않고 서로에게 메시지를 전송하여 통신합니다.
아래 코드 블록에 따라 함수를 인수로 받고 프로세스 식별자(PID)를 반환하는 spawn/1 함수를 사용하여 새 프로세스를 생성하려면 다음과 같이 하세요:

process_pid = spawn(fn ->
    IO.puts("Starting process")
end)

IO.puts("PID: #{inspect(process_pid)}") # PID: #PID<0.98.0>

한 프로세스에서 다른 프로세스로 메시지를 보내려면 수신자의 PID와 메시지를 지정하여 send/2 함수를 사용할 수 있습니다. 메시지를 받으려면 지정된 패턴과 일치하는 메시지가 올 때까지 기다리는 receive/1 함수를 사용할 수 있습니다. 메시지는 패턴과 순차적으로 매칭되므로 메시지 내용에 따라 수신할 메시지를 선택할 수 있습니다.
엘릭서에서 메시지를 보내는 방법은 다음과 같습니다:

send(process_pid, {:print_hello})

Elixir 프로세스는 동시에 실행되므로 겹치는 방식으로 실행될 수 있지만 반드시 여러 CPU 코어에서 병렬로 실행되지는 않습니다. 동시성 모델은 프로세스가 메시지를 전달하여 통신하는 액터 모델을 기반으로 합니다. 이 모델은 공유 상태를 없애고 메시지를 통해 통신하는 격리된 프로세스에 집중함으로써 동시 프로그래밍을 단순화합니다.
Elixir는 작업을 동시에 실행하기 위해 서로 다른 프로세스에서 작업을 예약하는 Task 모듈을 제공합니다. Task 모듈을 사용하여 여러 작업을 병렬로 실행하는 방법은 다음과 같습니다:

tasks = [
Task.async(fn -> IO.puts("Doing work 1") end),
Task.async(fn -> IO.puts("Doing work 2") end)
]

for task <- tasks do
 Task.await(task)
end

주어진 URL에 대한 모든 링크를 찾는 웹 크롤러를 만들어 보겠습니다.

우리가 구축하는 크롤러는 주어진 URL의 모든 링크를 가져오는 것을 목표로 주어진 URL에 대한 모든 링크를 크롤링합니다. 피해야 할 사항은 다음과 같습니다:

  • 중복 크롤링 링크 없음
  • 크롤러가 동시에 실행되며 다음과 같이 구성할 수 있습니다.
  • 크롤러의 실행 시간과 메모리 사용량 비교

이 튜토리얼에는 모든 코드가 포함되어 있지는 않지만 가장 중요한 부분을 보여드리겠습니다. 먼저 Elixir는 함수형 언어이므로 웹사이트를 재귀적으로 크롤링할 것입니다:

def run(start_url, scraper_fun, max_concurrency) do
    Stream.resource(
      fn -> {[start_url], []} end,
      fn
        {[], _found_urls} ->
          {:halt, []}
        {urls, found_urls} ->
          {new_urls, data} = crawl(urls, scraper_fun, max_concurrency)
          new_urls =
            new_urls
            |> List.flatten()
            |> Enum.uniq()
            |> Enum.reject(&diff_host?(URI.parse(start_url), &1))
            |> Enum.map(&to_string/1)
            |> Enum.reject(&Enum.member?(found_urls, &1))
          {data, {new_urls, new_urls ++ found_urls}}
      end,
      fn _ -> IO.puts("Finished crawling for '#{start_url}'.") end
    )
  end

  defp crawl(urls, scraper_fun, max_concurrency) when is_list(urls) do
    urls
    |> Task.async_stream(&crawl(&1, scraper_fun, max_concurrency),
      ordered: false,
      timeout: 15_000 * max_concurrency,
      max_concurrency: max_concurrency
    )
    |> Enum.into([], fn {_key, value} -> value end)
    # |> Enum.map(&crawl(&1, scraper_fun)) # To run without concurrency
    |> Enum.reduce({[], []}, fn {scraped_urls, scraped_data}, {acc_urls, acc_data} ->
      {scraped_urls ++ acc_urls, scraped_data ++ acc_data}
    end)
  end

따라서 크롤러는 중복 링크를 필터링하여 크롤링하고, 크롤러를 현재 도메인으로만 제한하며, 동시성으로 실행합니다. 다음은 Elixir에서 크롤러의 메모리 사용량입니다:

Rust

Rust는 정적이고 강력한 타이핑 및 컴파일 언어입니다. 그 결과 커뮤니티가 매우 빠르게 성장했습니다.

  • 구조는 완전히 객체 지향이 아닌 객체 지향 위에 존재합니다. Java의 인터페이스와 같은 특성이 존재합니다. 상속은 없지만 a/is 모델을 사용하여 상속을 지원합니다.
  • 컴파일 시 가비지 컬렉션으로 인해 메모리 안전성을 제공하고 성능이 향상됩니다.
  • Rust에는 가비지 컬렉션이 없지만 차용 검사기가 있습니다.
  • 멀티 스레드가 스레드 안전하지 않은 경우 컴파일 시 유형 오류가 발생합니다.

    Rust 의 장점

  1. 강력한 타입 시스템 언어
  2. 동시성이 가능하며 행위자 모델을 따릅니다.
  3. 컴파일러는 훌륭하고 사전에 상황을 파악합니다.
  4. 배포를 위해 출력에 정적 바이너리를 생성합니다.
  5. CPU 집약적인 애플리케이션과 같이 효율성성능이 필요한 시스템을 위한 시스템입니다.
  6. Async io는 Tokio 모듈과 함께 안정화되고 있습니다.
  7. 사용하지 않는 기능에는 비용을 지불하지 않습니다.
  8. 추상화 비용이 들지 않습니다.

Rust의 단점

  1. 학습 곡선이 더 높고, 코드 작성이 복잡합니다.
  2. 성장이 필요한 라이브러리와 커뮤니티
  3. 느린 컴파일러
  4. 100% 자체 지원 컴파일러는 아니며 LLVM 컴파일러에서 구현됩니다.

    Elixir와 Rust 비교

Rust는 안정적이고 효율적인 소프트웨어를 구축하는 프로그래밍 언어입니다. Rust의 초점 중 하나는 프로그램이 메모리 안전성을 보장하는 것입니다. Rust는 Elixir나 Go처럼 스레드나 코루틴을 지원하지는 않지만, 런타임을 구현하기 위한 하위 수준의 빌딩 블록을 제공합니다.
오늘은 동시 런타임을 빌드하지는 않겠지만, Rust에서 가장 많이 사용되는 비동기 런타임 중 하나를 사용하겠습니다: Tokio를 사용하겠습니다. 비동기와 동시성은 다르지만, Tokio 라이브러리의 일부를 사용하여 동시 런타임처럼 작동하도록 만들 수 있습니다.

다음은 Tokio 상자를 사용하여 동시 프로그램을 만드는 방법입니다:

  • 프로세스: Tokio에서 프로세스를 실행하려면 tokio::spawn을 사용할 수 있습니다. Tokio는 현재 스레드에서 실행할지 다른 스레드에서 실행할지 처리합니다. 또한 하나의 스레드에서만 실행하거나 여러 스레드에서 실행하도록 구성할 수도 있습니다.
  • 메시지: 프로세스 간 통신을 위해, Gol에서 채널처럼 작동하는 Tokio 메시지 채널 모듈 tokio::sync::mpsc를 사용할 수 있습니다.
  • 공유 상태: 공유 상태는 위험한 작업이지만 다행히도 Rust는 우리가 올바르게 수행하고 있는지 확인하는 데 도움을 줄 것입니다. Tokio를 사용하면 tokio::sync::Mutex를 사용하여 공유 상태에 안전하게 액세스할 수 있습니다.

다음은 Tokio를 사용한 간단한 비동기 작업의 예입니다:

use tokio::time::{sleep, Duration};

#[tokio::main] // 새 Tokio 런타임을 시작합니다.
async fn main() {
    let task = tokio::spawn(async {
    // 일부 작업을 시뮬레이션합니다.
    sleep(Duration::from_millis(50)).await;
    println!("작업이 완료되었습니다");
});

// 작업이 완료될 때까지 기다림
task.await.unwrap();
}

이 예제에서 tokio::spawn은 Tokio 런타임에서 새 작업을 시작하고, tokio::time::sleep은 일정 시간 후에 완료되는 퓨처를 생성합니다. await 키워드는 이러한 퓨처가 완료될 때까지 기다리는 데 사용되지만, 스레드를 차단하지 않고 다른 작업을 실행할 수 있도록 허용합니다.
동시성 프로그래밍에서는 여러 작업 간에 상태를 공유해야 하는 경우가 많습니다. 이를 위해 일반적으로 메시지 전달을 사용하는 것이 더 안전하며 코드를 더 쉽게 추론할 수 있기 때문에 선호되는 방법입니다. 하지만 상태 공유가 필요한 경우도 있습니다.
작업 간에 상태를 공유하려면, std::sync의 일부인 Arc를 제외한 tokio::sync 모듈의 일부인 Arc, RwLock, Mutex 및 Semaphore와 같은 유형을 사용할 수 있습니다. 이러한 유형을 사용하면 여러 작업에서 변경 가능한 상태를 안전하게 공유할 수 있습니다:

  1. Arc(원자 참조 카운트): Arc를 사용하면 작업이나 스레드에서 공유할 모든 타입이나 구조체를 래핑할 수 있습니다. 예를 들어 Arc는 User를 힙에 저장합니다. 그런 다음 해당 인스턴스를 복제하여 힙에서 User를 참조하는 새 Arc 인스턴스를 만들 수 있습니다.
  2. Mutex(상호 제외): 한 번에 최대 하나의 스레드만 일부 데이터에 액세스하거나 변경할 수 있도록 합니다.
  3. RwLock(읽기-쓰기 잠금): 쓰기자가 잠그지 않는 한, 여러 작업 또는 스레드가 데이터를 읽을 수 있도록 합니다.
  4. 세마포어: 세마포어는 동시성에서와 같이 워커를 구현하는 데 사용할 수 있습니다. 예를 들어, 데이터가 1,000개인데 1,000개의 워커를 스폰하고 싶지 않은 경우 세마포어를 사용하면 스폰할 워커 수를 제한할 수 있습니다. 세마포어는 워커가 많다고 해서 프로젝트가 더 빨리 작동하는 것은 아니기 때문에 유용합니다.

ArcMutex의 예제

use std::sync::Arc;
use tokio::sync::Mutex;
use tokio::spawn;

#[tokio::main]
async fn main() {
    let data = Arc::new(Mutex::new(0));

    let data1 = Arc::clone(&data);
    let task1 = spawn(async move {
        let mut lock = data1.lock().await;
        *lock += 1;
    });

    let data2 = Arc::clone(&data);
    let task2 = spawn(async move {
        let mut lock = data2.lock().await;
        *lock += 1;
    });

    task1.await.unwrap();
    task2.await.unwrap();

    assert_eq!(*data.lock().await, 2);
}

이 예제에서는 일부 데이터를 저장하기 위해 Arc<Mutex<i32>>가 생성됩니다. 그런 다음 각각 데이터를 증가시키는 두 개의 작업이 생성됩니다. Mutex는 한 번에 하나의 작업만 데이터에 액세스할 수 있도록 보장하기 때문에 데이터 경합이 발생하지 않으며 최종 결과는 예상대로 나타납니다.
한 가지 주목할 점은 Tokio에서 제공하는 잠금(예: Mutex 및 RwLock)은 비동기식이며, 경합이 발생할 때 전체 스레드를 차단하지 않는다는 점입니다. 대신 현재 작업만 차단하여 다른 작업이 동일한 스레드에서 계속 실행될 수 있도록 합니다.
이제 Rust와 Tokio를 사용해 간단한 웹 크롤러를 만들어 보겠습니다. 먼저 크롤러를 실행할 특성을 정의해 보겠습니다:

use crate::error::Error;
use async_trait::async_trait;

pub mod web;

#[async_trait]
pub trait Spider: Send + Sync {
    type Item;

    fn name(&self) -> String;
    fn start_url(&self) -> String;
    async fn scrape(&self, url: String) -> Result<Vec<Self::Item>, Error>;
}

Spider를 구현합니다.

impl WebSpider {
    pub fn new(start_url: String, worker: usize) -> Self {
        let http_timeout = Duration::from_secs(4);

        let http_client = Client::builder()
            .timeout(http_timeout)
            .user_agent(
                "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0",
            )
            .pool_idle_timeout(http_timeout)
            .pool_max_idle_per_host(worker)
            .build()
            .expect("WebSpider: Building HTTP client");

        WebSpider {
            http_client,
            start_url,
        }
    }
}

#[async_trait]
impl super::Spider for WebSpider {
    type Item = String;

    fn name(&self) -> String {
        String::from("WebSpider")
    }

    fn start_url(&self) -> String {
        self.start_url.to_string()
    }

    async fn scrape(&self, url: String) -> Result<Vec<String>, Error> {
        println!("Scraping url: {}", &url);
        let raw_url = Url::parse(&url)?;
        let host = raw_url.scheme().to_owned() + "://" + raw_url.host_str().unwrap();

        let start = Instant::now();
        let body_content = self.http_client.get(&url).send().await?.text().await?;

        let seconds = start.elapsed().as_secs_f64();
        if seconds > 3.0 {
            println!(
                "Parsing res body: {} in \x1B[32m{:.2}s\x1B[0m",
                &url, seconds
            );
        }
        let parser = Html::parse_document(body_content.as_str());
        let selector = Selector::parse("a[href]").unwrap();

        let links: Vec<String> = parser
            .select(&selector)
            .filter_map(|element| element.value().attr("href"))
            .filter_map(|href| {
                let parsed_link = raw_url.join(href);
                match parsed_link {
                    Ok(link) => {
                        let mut absolute_link = link.clone();
                        absolute_link.set_fragment(None);
                        absolute_link.set_query(None);
                        if absolute_link.to_string().starts_with(&host) {
                            Some(absolute_link.to_string())
                        } else {
                            None
                        }
                    }
                    Err(_) => None,
                }
            })
            .collect();

        Ok(links)
    }
}

실행

$ ./crawler_rust --work 10 --url https://react.dev

Elixir, Rust 성능의 벤치마크

지금까지 웹 크롤러를 Rust, Elixir에 구현했습니다. 이제 각각의 성능을 확인하기 위해 벤치마크를 실행해 보겠습니다. 작업을 완료하는 데 걸리는 시간과 테스트 중에 사용되는 메모리 양이라는 두 가지를 측정하고자 합니다. 크롤러는 https://react.dev 도메인의 모든 링크를 가져옵니다. 127개의 링크를 가져올 것으로 예상됩니다.

시간 측정 벤치마크

10개의 동시성 작업자를 사용하여 각 웹 크롤러가 링크를 가져오는 데 걸린 시간은 다음과 같습니다:

  • Elixir: 7.6초
  • Rust: 7.2초

HTTP 요청을 수행하는 데 시간이 걸립니다. 이는 각 연결에서 SSL/TLS 핸드셰이크가 생성되기 때문입니다. 기본 Go HTTP 라이브러리는 이 두 가지를 동시에 실행하기 때문에 이 시나리오에서 Go의 성능이 가장 우수합니다.
Elixir와 Rust를 모두 최적화하여 TLS/TLS 핸드셰이크를 한 번만 생성하고 워커 전체에서 사용하도록 할 수 있습니다:

TLS/SSL 핸드셰이크를 한 번만 만들고 작업자 전체에서 사용해야 합니다:

Web Crawler Performance With Elixir, Rust, And Go

다음은 50명의 워커의 결과입니다. 더 많은 동시성 워커를 사용한다고 해서 크롤러의 속도가 향상되는 것은 아니며, 네트워크 지연에 의해 제한되기 때문입니다

Web Crawler Result With 50 Workers

다음은 동시성(Concurency)를 조외한 밴치마크 입니다.

Web Crawler Without Concurrency

메모리 사용 밴치마크

메모리 사용량과 관련해서는 흥미로운 점이 있습니다:

  1. Elixir: 295MB
  2. Rust: 50MB

메모리 사용량에서는 Rust가 더 나은 성능을 보이는 반면, Elixir의 성능은 비슷하게 떨어지는 것을 알 수 있습니다:

Memory Usage Comparison Across Elixir, Rust, And Go

결론

이 튜토리얼에서는 Elixir, Rust로 동시 프로그램을 실행하는 방법을 배웠습니다. 각 언어마다 동시성을 처리하는 방법에 대한 고유한 아이디어가 있지만, Go의 기본 라이브러리는 동시성을 훌륭하게 지원하지만 메모리를 많이 사용한다는 것을 알 수 있었습니다. 이는 힙에 메모리를 할당하고 가비지 컬렉션을 사용하여 메모리를 정리하기 때문입니다. 이로 인해 GC가 정리를 수행할 때 메모리 사용량이 많아지고 일부 결함이 발생할 수 있습니다.

Elixir에서는 프로세스를 스폰하고 프로세스 간 공유 상태를 관리하는 것이 얼마나 쉬운지 확인했습니다. 하지만 동시에 Elixir에서 동시 프로그램의 성능을 향상시키는 것은 쉽지 않습니다. Elixir는 가비지 컬렉션을 사용해 메모리를 관리하기 때문에 Go과 비슷한 성능을 발휘합니다.

Rust로 동시 프로그램을 작성하는 것은 쉽지 않지만, Rust의 소유권 및 타입 시스템 덕분에 메모리 안전성을 확보할 수 있다는 이점이 있습니다. Rust는 가비지 컬렉션을 사용하지 않기 때문에 가비지 컬렉션을 사용하는 골랑이나 엘릭서보다 메모리 사용 측면에서 더 효율적입니다.

이 글의 전체 소스코드는 여기에서 확인할 수 있습니다(https://github.com/ahmadrosid/elixir-go-rust). 궁금한 점이나 공유하고 싶은 추가 정보가 있으면 언제든지 알려주세요.

반응형

'개발' 카테고리의 다른 글

2024년 프로그래밍 랭킹  (1) 2024.01.02
gitlab 설치(apache --proxy--> gitlab)  (0) 2023.12.27
vscode dev containers  (1) 2023.12.22
svn to git 마이그레이션 (맥)  (0) 2023.12.13
intelliJ gitlab plugin(merge request) 연결 오류  (0) 2023.08.23

여기에서 나온 정보를 학습한 내용입니다.

Visual Studio Code Dev Containers 확장을 사용하여 컨테이너 기반 개발 환경을 가져오고 만들고 구성합니다.

이 모듈을 마치면 다음을 수행할 수 있습니다.

  • Visual Studio Code Dev Containers 확장을 설치합니다.
  • Docker에서 프로젝트를 로드 및 연결합니다.
  • 로컬 컴퓨터에서 컨테이너의 포트에 액세스합니다.
  • 컨테이너에서 작업하는 동안 설정을 사용자 지정합니다.
  • 컨테이너 환경에 소프트웨어를 추가합니다.

Visual Studio Code 개발 컨테이너 확장을 사용하여 Docker 컨테이너 내에서 개발할 수 있습니다.

다양한 언어와 런타임 환경을 중심으로 소프트웨어 컨설팅을 수행하는 에이전시에서 근무한다고 가정합니다. 모든 개발자가 Visual Studio Code를 사용하고 있습니다. 에이전시에서는 수십 개의 프로젝트가 진행 중이며, 각각 고유한 구성 및 런타임 요구 사항이 있습니다. 에이전시 개발자는 먼저 머신을 설정하거나 구성하지 않고도 모든 프로젝트에서 작업할 수 있어야 합니다.

이 모듈에서는 기존 프로젝트에 구성 파일을 추가합니다. 이러한 파일은 프로젝트가 “작동하는” 환경을 빌드하는 방법을 Visual Studio Code에 알려줍니다. Dev Container 구성을 사용하여 런타임 환경을 구성합니다. 또한 Docker와 Visual Studio Code가 있는 모든 사용자가 사용할 수 있는 개발 환경의 구성을 자동화합니다.

필수 구성 요소

  • 소프트웨어 개발에 대한 기본 지식(예: 코드 실행 또는 새 언어 설치의 의미)
  • Docker 및 기본 Docker 지식:
  • Git 및 Git 리포지토리에 대한 기본 지식

연습 - 프로제트 준비

샘플 리포지토리 복제

  1. Docker Desktop이 머신에 설치되어 실행 중인지 확인합니다.
  2. 샘플 리포지토리의 URL을 클립보드에 복사합니다.
    https://github.com/MicrosoftDocs/mslearn-python-products
  3. Visual Studio Code의 새 인스턴스를 엽니다.
  4. 사이드바에서 리포지토리 복제 단추를 선택하거나 F1 키를 눌러 명령 팔레트를 열고 Git: Clone을 검색합니다.
  5. 클립보드에서 URL을 붙여넣습니다.
  6. 디스크에서 프로젝트를 복제할 수 있는 위치를 선택합니다.
  7. Visual Studio Code의 알림에서 열기를 선택합니다.
  8. 작성자를 신뢰할 수 있는지 묻는 팝업이 표시되면 예, 작성자를 신뢰합니다를 선택합니다.

dev container

이 확장의 작동 방식

Dev Containers extension 을 사용하면 특정 기술 스택 또는 종속성이 이미 설정된 개발 컨테이너를 가져와 프로젝트를 열고, 로컬 머신에 아무것도 다운로드하지 않고도 코드가 제대로 작동하는지 확인할 수 있습니다. Dev Containers 실행 중인 컨테이너에 Visual Studio Code를 연결하는 방식으로 작동합니다. 작업 영역 파일은 로컬 파일 시스템에서 탑재되거나 컨테이너에 복사 또는 복제됩니다.

Visual Studio Code Extension은 컨테이너 안에 설치되고 내부에서 실행됩니다. 여기서 확장은 도구, 플랫폼, 파일 시스템에 대한 모든 권한을 갖습니다. 개발자에게 이 환경은 Visual Studio Code에서 정상적으로 프로젝트를 연 것과 같습니다.

다른 컨테이너에 연결하는 것만으로 전체 개발 환경을 원활하게 전환할 수 있습니다. 이 확장은 ‘.devcontainer’ 라는 폴더에 포함된 몇 가지 구성 파일을 기반으로 모든 설정을 처리합니다.

기존 프로젝트에 개발 컨테이너 추가

    1. F1 키를 눌러 명령 팔레트를 엽니다.
    2. Dev Container: new Dev Container를 누릅니다
    3. python 3를 선택합니다
    4. default 버전을 선택합니다.

[!info] 저는 microsoft 기본가이인 3.11 버전으로 하면 container가 생성이 안되는 일이 있었습니다. 그래서, default 버전으로 변경했습니다.

    1.  
    2. container가 실행되는 것을 확인할 수 있습니다.
    3. 명령줄에서 close remote connection을 한 후에 다시 프로젝트 파일을 열면 현재 로컬 폴더를 포함하는 Folder contians a Dev Container configuration file. Reopen folder to develop in a contain라는 알림창을 확인할 수 있습니다.

만약 이게 안 나온다면, 명령 줄에서 dev container: contain

  1.  

python 프로젝트 실행

종속성 설치

pip3 install --user -r requirements.txt
pip3 install flask

실행

$ python3 app.py

...
[notice] A new release of pip is available: 23.2.1 -> 23.3.2
[notice] To update, run: pip install --upgrade pip
vscode ➜ /workspaces/mslearn-python-products (main) $ python3 app.py 
 * Serving Flask app 'app'
 * Debug mode: on
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:5000
Press CTRL+C to quit
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 717-269-910

[!info] flask 오류로 실행이 안된다면, pip3 install --upgrade flask 를 실행해서 업그레이드 후 진행 합니다.

실행이 되는 것을 확인했다.

project 편집기 설정 사용자 지정

에이전시의 프로젝트 중 하나에 대해 개발 컨테이너를 설정했습니다. 이제 이 프로젝트는 Docker 및 Dev Containers 확장이 있는 사용자를 위해 “저절로 작동”합니다. 여전히 종속성을 설치해야 합니다. 잘 모르는 몇 가지 Visual Studio Code 확장이 필요할 수도 있습니다.

다행히 devcontainer.json 파일을 사용하여 모든 프로젝트 설정을 완전하게 사용자 지정하고 자동화할 수 있습니다.

devcontainer.json 자세히 보기

Products Dashboard 프로젝트의 .devcontainer/devcontainer.json 파일에 있는 기본 옵션을 살펴보겠습니다. 한 번에 모두 확인하려면 다소 길기 때문에 섹션별로 살펴보겠습니다.

빌드 구성

image 속성은 컨테이너 이미지로 알려져 있는 항목을 기준으로 컨테이너를 만드는 방법을 정의합니다.

JSON

"image": "mcr.microsoft.com/devcontainers/python:0-3.11"
},

이 이미지는 devcontainers/images 리포지토리에서 호스트되며 여기서 자세히 확인할 수 있습니다.

Dockerfile 또는 Docker Compose 파일로 알려진 파일을 사용하여 설정을 구성할 수도 있습니다. 이러한 파일은 .devcontainer 폴더에 저장되며 추가 소프트웨어 설치와 같은 특정 설치 요구 사항을 추가로 구성할 수 있습니다. dev container 설명서에서 자세히 알아볼 수 있습니다.

기능

Dev Containers Extension은 자체 포함되고 공유 가능한 설치 코드 단위 및 개발 컨테이너 구성입니다. 이름은 그 중 하나를 참조하면 사용자 또는 협력자가 사용할 수 있도록 개발 컨테이너에 도구, 런타임 또는 라이브러리 "기능"을 빠르고 쉽게 추가할 수 있다는 아이디어에서 비롯되었습니다.

VS Code 명령 Dev Containers: 개발 컨테이너 구성 파일 추가를 사용하는 경우 Git 또는 Azure CLI 설치와 같은 기존 개발 컨테이너 구성을 사용자 지정하는 스크립트 목록이 표시됩니다.

프로젝트 설정

파일의 뒤쪽 섹션에서는 프로젝트 구성을 직접 처리합니다.

customizations는 VS Code 및 GitHub Codespaces와 같은 개발 컨테이너를 지원하는 제품에 대한 제품별 속성을 설정합니다.

예를 들어 컴퓨터별 설정을 컨테이너에 복사하도록 vscode.settings를 설정할 수 있습니다. 고유한 Visual Studio Code 설정에 해당 설정이 있을 수도 있습니다. settings에 프로젝트를 추가하여 이러한 프로젝트를 여는 누구든지 이러한 특정 VS Code 설정을 가져오도록 할 수 있습니다.

이 Python 컨테이너에서는 기본 이미지 mcr.microsoft.com/devcontainers/python:0-3.11에서 이러한 설정을 볼 수 있습니다. 이러한 설정은 사용자에게 향상된 Python 편집 환경을 제공합니다.

  • extensions 배열을 사용하면 컨테이너에 연결할 때 Visual Studio Code에 설치할 Visual Studio Code 확장을 지정할 수 있습니다. Dev Containers를 사용하는 경우 일반적인 Visual Studio Code 설정과 이미 설치한 모든 확장은 표시되지 않습니다. 여기에서 확장은 ID로 지정됩니다.

postCreateCommand

postCreateCommand 속성을 사용하면 컨테이너가 생성된 후 원하는 명령을 실행할 수 있습니다. 첫 번째 연습에서는 종속성을 설치하기 위해 pip3 명령을 실행해야 했습니다. 하지만 그 방법을 어떻게 알 수 있나요? 방법을 모를 수도 있습니다. 자동으로 수행되어 다른 사용자가 걱정하지 않아도 되도록 여기에서 구성할 수 있습니다.

다음 연습에서는 프로젝트의 여러 부분을 자동화하여 다른 개발자가 즉시 성공할 수 있도록 devcontainer.json 파일을 수정합니다.

vscode extension 자동 설치

remote 로 열려 있는 vscode에서 extension을 설치하고, 설치한 extension을 마우스 우클릭을 누른 다음에, Add to devcontainer.json을 누른다.

~/.devcontain/devcontainer.json 에 다음 값이 추가된 것을 확인할 수 있다.

{
    "name": "Python 3",
    // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
    "image": "mcr.microsoft.com/devcontainers/python:1-3.12-bullseye",
    "customizations": {
        "vscode": {
            "extensions": [
                "wholroyd.jinja"
            ]
        }
    }
}

python 종속성 자동 설치

flaks 버전이 낮기 때문에, devcontainer.json파일을 다음과 같이 수정한다.

# Flask Framework
Flask==3.0.0

devcontainer.json에 아래 내용을 추가 한다.

...
    "postCreateCommand": "pip3 install --user -r requirements.txt"

rebuild 을 다시 선택한다.

이제 컨테이너가 사용자 지정되고 에이전시에 대해 자동화됩니다. Dev Containers를 사용하여 이 프로젝트를 여는 개발자는 즉시 프로젝트를 실행하고 코드 작성을 시작할 수 있습니다.

# 기존 컨테이너에 소프트웨어 추가

사용자 지정 컨테이너는 에이전시에 적합합니다. Dev Containers의 기능을 사용하여 미리 구성된 개발 컨테이너를 추가할 수 있었으며, 지금까지의 연습을 통해 devcontainer.json 파일을 활용해 환경을 사용자 지정할 수 있었습니다. 그러나 해당 이미지나 미리 구성된 개발 컨테이너에서 사용할 수 있는 것 외에 다른 소프트웨어를 추가하려면 어떻게 해야 할까요?

위 페이지에서 추가할 수 있는 기능들에 대해서 확인 할수 있습니다

devcontainer.json파일에 아래와 같이 추가 합니다.

"features": {
    "ghcr.io/devcontainers/features/node:1": {
        "version": "18"
    }
}

rebuild 를 실행하면 node가 추가 설치 된 것을 확인할 수 있습니다

$ node -v

rust function 추가하기

"features": {
    "ghcr.io/devcontainers/features/rust:1": {
        "version": "1.70.0"
    }
}
반응형

준비

아래와 같은 프로그램들이 설치 되어 있어야 합니다.

  • svn: svn소스
  • git: 깃
  • git-svn: 마이그레이션 도구

    MAC에서

$ brew install git git-svn svn

git에 remote repo를 생성해 놓습니다.

SVN 에서 사용자 가져오기

$ svn log -q
r38 | hello | 2016-04-29 15:44:52 +0900 (금, 29  4 2016)
------------------------------------------------------------------------
r37 | hello | 2016-04-29 15:00:44 +0900 (금, 29  4 2016)
------------------------------------------------------------------------

users.txt 사용자 매핑파일 생성하기

sample1 = sample1 <sample1@exmaple.com>
sample2 = sample2 <sample2@exmaple.com>
sample3 = sample3 <sample3@exmaple.com>
VisualSVN Server = VisualSVN Server <VisualSVN_Server@exmaple.com>

|> [!caution] 사소한 계정들 모두 정보가 있어야 합니다. 하나라도 빠지면 안됩니다.

Author: VisualSVN Server not defined in users.txt file 와 같은 에러가 발생합니다.

Migration

$ git-svn clone --authors-file users.txt --no-metadata --authors-file 'users.txt' https://123.223.12.22/svn/example/trunk
...
...
        M       src/main/java/com/exmaple/sample/see/weapojfawService.java
        M       src/main/java/com/exmaple/sample/service/real/HellowService.java
        M       src/main/java/com/exmaple/sample/util/excel/Excel.java
        M       src/main/java/com/exmaple/sample/util/excel/Excel2.java
        M       src/main/webapp/WEB-INF/views/fi/rt/netAssetsMonthly.html
r3029 = f317a56a69906edafdf641e2b9cc4388defb7f07587 (refs/remotes/git-svn)

위와 같은 식으로 된다

remote push

$ git remote add origin http://gitlab.com:port/remote_git.git
$ git push -u origin master
반응형

강좌

  1. Elixir School ... 무료로 기본을 배울 수 있다.

elixir 함수형프로그램의 특징

  • 변환 프로그래밍: 프로그래밍은 데이터를 변환하는 것이 중식

  • 데이터를 변환하는 것은 함수이며, 함수들의 조합이 프로그램

  • 함수들을 작고 한가지 목적에만 집중하게 만들수록, 더 유연하고 테스트 쉬운 구조

  • 로직 설계의 변경은 함수의 재조합

    메타프로그래밍과 매크로

  • 메타프로그래밍: 코드로 코드를 작성하는 방법

  • 고수준의 우아한 문법으로 저수준의 코드 조작

  • 컴파일 타임에 코드 최적화: 성능 향상과 깔끔한 코드를 동시에 잡을 수 있음

  • 매크로를 통해 스스로 확장, 안정적이고 성숙된 문법들

  • 엘릭서 표준 라이브러리의 Logger 모듈의 디버깅 함수

Actor 동시성 모델

  • 엘릭서에서 액터는 프로세스
  • 프로세스는 특정 작업을 수행
  • 서로 결리된 프로세스들은 메세지를 보내 소통
  • 프로세스는 ErlangVM(BEAM)위에서 돌아가며 자원이 매우 적게 사용

예제

  1. 엑셀을 파싱하여 등록할 사용자 정보 추출(Parser)
  2. 사용자 등록(Register)
  3. 등록 결과 메세지 전송(Reporter)

    설치

MAC

$ brew install elixir

interactive mode

$ iex
Erlang/OTP 26 [erts-14.0.2] [source] [64-bit] [smp:10:10] [ds:10:10:10] [async-threads:1] [jit] [dtrace]

Interactive Elixir (1.15.7) - press Ctrl+C to exit (type h() ENTER for help)
iex>

Package 관리

javascript의 npm과 같이 package 관리 메니저가 별도로 있습니다. mix hex 를 통해서 관리할 수 있습니다.

Hex v2.0.6
Hex is a package manager for the Erlang ecosystem.

Available tasks:

mix hex.audit                                         # Shows retired Hex deps for the current project

mix hex.build                                         # Builds a new package version locally

mix hex.config                                        # Reads, updates or deletes local Hex config
mix hex.config KEY                                    # Get config value for KEY
mix hex.config KEY --delete                           # Delete config value for KEY
mix hex.config KEY VALUE                              # Set config KEY to VALUE

mix hex.docs fetch PACKAGE [VERSION]                  # Fetch documentation for offline use
mix hex.docs offline PACKAGE [VERSION]                # Open a browser window with offline documentation
mix hex.docs online PACKAGE [VERSION]                 # Open a browser window with online documentation

mix hex.info                                          # Prints Hex information
mix hex.info PACKAGE [VERSION]                        # Prints package information

mix hex.organization auth ORGANIZATION                # Authorize an organization
mix hex.organization deauth ORGANIZATION              # Deauthorize and remove organization
mix hex.organization list                             # List all authorized organizations
mix hex.organization key ORGANIZATION generate        # Generate organization key
mix hex.organization key ORGANIZATION revoke KEY_NAME # Revoke key
mix hex.organization key ORGANIZATION revoke --all    # Revoke all keys
mix hex.organization key ORGANIZATION list            # List keys

mix hex.outdated                                      # Shows outdated Hex deps for the current project
mix hex.outdated [APP]                                # Shows outdated Hex deps for the given dependency

mix hex.owner add PACKAGE EMAIL_OR_USERNAME           # Adds an owner to package
mix hex.owner transfer PACKAGE EMAIL_OR_USERNAME      # Transfers ownership of a package to another user or organization
mix hex.owner remove PACKAGE EMAIL_OR_USERNAME        # Removes an owner from package
mix hex.owner list PACKAGE                            # List all owners of a given package
mix hex.owner packages                                # List all packages owned by the current user

mix hex.package fetch PACKAGE [VERSION] [--unpack]    # Fetch the package
mix hex.package diff APP VERSION                      # Diff dependency against version
mix hex.package diff PACKAGE VERSION1 VERSION2        # Diff package versions
mix hex.package diff PACKAGE VERSION1..VERSION2       # Diff package versions

mix hex.publish                                       # Publishes a new package version
mix hex.publish package                               # Publish current package
mix hex.publish docs                                  # Publish current docs
mix hex.publish package --revert VERSION              # Reverts package on given version
mix hex.publish docs --revert VERSION                 # Reverts docs on given version
mix hex.publish --revert VERSION                      # Reverts given version

mix hex.registry build PUBLIC_DIR                     # Build a local registry

mix hex.repo add NAME URL                             # Add a repo
mix hex.repo set NAME                                 # Set config for repo
mix hex.repo remove NAME                              # Remove repo
mix hex.repo show NAME                                # Show repo config
mix hex.repo list                                     # List all repos

mix hex.retire PACKAGE VERSION REASON                 # Retires a package version
mix hex.retire PACKAGE VERSION --unretire             # Unretires a package

mix hex.search PACKAGE                                # Searches for package names

mix hex.sponsor                                       # Show Hex packages accepting sponsorships

mix hex.user register                                 # Register a new user
mix hex.user whoami                                   # Prints the current user
mix hex.user auth                                     # Authorize a new user
mix hex.user deauth                                   # Deauthorize the user
mix hex.user key generate                             # Generate user key
mix hex.user key revoke KEY_NAME                      # Removes given key from account
mix hex.user key revoke --all                         # Revoke all keys
mix hex.user key list                                 # Lists all keys associated with your account
mix hex.user reset_password account                   # Reset user account password
mix hex.user reset_password local                     # Reset local password


Further information can be found here: https://hex.pm/docs

빌드

$ mix escript.build
$ ./example_app --upcase Hello
HELLO

다른 프로그램 소스를 사용해서 빌드하는 방법

$ mix deps.get
$ mix compile

개발툴

표준 라이브러리

  • 엘릭서에 내장 된 표준 테스트 라이브러리 제공
  • 매크로를 사용하여 간편한 문법
    test "elixir test example" do
    assert something_is_valid()
    assert expect_list() == actual_list()
    assert expect_error_log() =~ "error"
    end
  • document + test = doctest
    defmodule ExampleCode do
    @moduledoc """
    @doc """
    어떻게어떻게 하는 함수
    """
    def sum(a, b) do
      a + b
    end

iex

$ iex

livebook

python의 jupiter와 비슷한 기능

IDE

정식으로 erlang, elixir 만 지원하는 에디터는 없습니다. 커뮤니티에서는 neovim를 추천합니다. vscode 에서도 잘 작동합니다.

  • gen_lsp link
  • credo link
  • elixir-lint

    neovim

여기를 참고해서 설정했습니다.

tree-sitter가 설치되어 있는 상태에서

:TSInstall elixr

vscode

플러그인 설치

  • elixir-tools

    jetbrains intelliJ

SDK 파일을 불러 와야 하는데, brew로 설치를 했을 경우에는 폴더가 버전마다 다르기 때문에 위치를 잘 찾아야 한다.

elixr 파일 위치

$ readlink (which elixir)
../Cellar/elixir/1.15.7/bin/elixir

erlang 파일 위치

$ readlink (which erlc)
../Cellar/erlang/26.0.2/bin/erlc

파일 위치에서 버전명까지 넣어주면 된다.

  1. elixir plugin 설치
  2. SDK 설정
    1. elixir > SDKs: /opt/homebrew/Cellar/elixir/1.15.7
    2. elixir > Internal Erlang SDKs: /opt/homebrew/Cellar/erlang/26.0.2
반응형

설치

백업

mv ~/.config/nvim ~/.config/nvim.bak

Clean neovim folders (Optional but recommended)

mv ~/.local/share/nvim ~/.local/share/nvim.bak
mv ~/.local/state/nvim ~/.local/state/nvim.bak
mv ~/.cache/nvim ~/.cache/nvim.bak

Clone the repository

git clone --depth 1 https://github.com/AstroNvim/AstroNvim ~/.config/nvim
nvim

1. 기본 맵핑 설정변경(기본설정)

`leader key` 가 기본적으로 `SPACEBAR` 로 설정되어 있습니다. 개인적으로는 vim 에서 전통적으로 사용하는 \ 키를 변경하고 싶지않아 변경하였습니다.
  1. lua/astronvim/optionslua ... leader key 설정변경
  2. lua/astronim/mapping.lua ... 기타 키 맵핌 설정
    -- mapleader = " ", -- 기본설정
    mapleader = "\\",k

2. 기타 설정 변경

leader key 변경

~/.config/nvim/lua/user/init/lua에 기타 설정들을 변경할 수 있습니다.

아래샐정은 leaderkey 를 변경하고 , mapping.lua에 설정되어 있는 pane split 기능에 대한 단축키를 disabled 처리 한 것입니다.

return {
  options = {
    g = {
      mapleader = "\\"
    }
  },
  mappings = {
    n = {
      ["|"] = false,
      ["\\"] = false
    }
  },
  plugins = {
    init = {
      { "ofejwpofwpeojf",
        config = function()
          require("rust-tools").setup {
          server = astrovim.lsp.server_settings "rust_analyzer"
          }
      }
    }
  }
}

3. plugin 설치

~/.config/nvim/lua/user/plugins/ 폴더에 플러그인 파일들을 생성하면 자동으로 파일을 읽어들인다.

nvim-surround

~/.config/nvim/lua/plugin/nvim-surround.lua에 아래 내용을 삽입

return {
  {
    "kylechui/nvim-surround",
    version ="*",
    event = "VeryLazy",
    config = function()
      require("nvim-surround").setup({
        -- Configuration here, or leave empty to use defaults
      })
    end,
  },
}

i

codeium

~/.config/nvim/lua/plugins/codium.lua 파일에 아래 내용을 추가하고 저장하면, 자동으로 플러그인을 인식한다.

return {
  {
    'Exafunction/codeium.vim',
    event = 'BufEnter',
    config = function ()
    -- Change '<C-g>' here to any keycode you like.
      vim.keymap.set('i', '<C-g>', function () return vim.fn['codeium#Accept']() end, { expr = true })
      vim.keymap.set('i', '<c-;>', function() return vim.fn['codeium#CycleCompletions'](1) end, { expr = true })
      vim.keymap.set('i', '<c-,>', function() return vim.fn['codeium#CycleCompletions'](-1) end, { expr = true })
      vim.keymap.set('i', '<c-x>', function() return vim.fn['codeium#Clear']() end, { expr = true })
      vim.keymap.set("n", "<leader>;", function()
        if vim.g.codeium_enabled == true then
          vim.cmd "CodeiumDisable"
        else
          vim.cmd "CodeiumEnable"
        end
      end, { noremap = true, desc = "Toggle Codeium active" })
    end,
  }
}

vim에 들어가서 명령모드에서 아래와 같이 입력하면, 인증을 시작한다.

:Codeium Auth
반응형

gitlab 을 구현한 시스템

메일 WEB 서버에서 Reserve Proxy Server를 통해서 자체 설치한 gitlab과 연결을 하고 있는 구조입니다.

flowchart BR
    A[apache web server] --Reserve Proxy--> B[gitlab server on-promise]

일반 apache 설정에서는 gitlab 에 요청을 하면 하위 URL에 제대로 요청을 할 수가 없습니다. 이를 해결하기 위해서 apache 에 reserve proxy 에 관한 설정을 해줘야 합니다.
저는 아래와 같이 80 port 로 들어온 요청을 443 으로 redirect 시켜서 서버 구성을 했습니다.

<VirtualHost *:80>
        ServerName      gitlab.domain.com
        Redirect        / https://gitlab.domain.com
</VirtualHost>
<VirtualHost *:443>
        ServerName      gitlab.domain.com

        ProxyRequests Off
        ProxyPreserveHost On
        ProxyPass / http://192.168.0.67:8000/
        ProxyPassReverse / http://192.168.0.67:8000/

        <Proxy *>
                Order allow
                Allow from all
        </Proxy>
        ....
</VirtualHost>

여기서 추가를 해 줘야 하는 옵션은 두가지 입니다.

  1. nocanon: ProxyPass 디렉티브와 함께 사용합니다.
    프록시 서버가 요청 URL을 정규화 하지 않도록 지정합니다. 정규화는 URL 경로를 표준화하여 중복된 슬래시를 제거하고 상위 디렉토리 참조를 해결하는 과정입니다. 원래 요청 URL의 경로를 그대로 유지할 수 있습니다.

  2. AllowEncodedSlashes NoDecode: ProxyPass 디렉티브와 함께 사용합니다.
    프록시 서버가 인코딩된 슬래시를 디코딩 하지 않도록 지정합니다. 기본적으로 Apache 는 인코딩된 슬래시를 디코딩하여 처리합니다. 인코딩된 슬래시를 그대로 유지할 수 있습니다. 일부 어플리케이션에서 인코딩 된 슬래시를 사용하는 경우 유용합니다.

<VirtualHost *:443>
        ServerName      gitlab.domain.com

        ProxyRequests Off
        ProxyPreserveHost On
        ProxyPass / http://192.168.0.67:8000/ nocanon
        ProxyPassReverse / http://192.168.0.67:8000/

        ....
        AllowEncodedSlashes NoDecode
</VirtualHost>
반응형

+ Recent posts