Lighthouse Dev
Dev 기술 이야기
파이썬의 동시성 관리 : GIL 과 멀티 스레딩
0. 들어가며 저번 시간에는 동시성. 즉, 제어권에 대한 Blocking/NonBolocking. 또 작업의 순서를 논하는 Sync/Async에 대해 간단하게 살펴보았다. 그렇다면 이번 시간에는 다음 순서로 파이썬의 GIL 및 스레드 환경에 대해 살펴보자. 0-1. 들어가기 앞서 ! 오늘 발표를 조금 더 잘 이해할 수 있도록 하기 위해, 몇가지 용어에 대한 설명을 준비하였다. 메모리란 ? 메모리는 컴퓨터가 프로그램과 데이터를 저장하고 처리하는 데 사용되는 저장 공간이다. 프로그램의 실행 중에 생성되는 데이터는 물리적인 메모리에 저장 되며(주로 RAM), 이 데이터는 스레드가 실행되면서 읽고 쓰게 된다. 프로세스란 ? 실행 중에 있는 프로그램을 의미한다. 작업(Task)과 같은 의미로 쓰인다. 프로세스는 최소 하나의 스레드를 가지는데, 실제로 작업(Task)이 스레드 단위로 동작한다. 스레드란 ? 스레드는 프로그램 내에서 실행되는 흐름의 단위. 일반적으로 한 프로그램은 하나의 스레드를 가지고 있지만, 프로그램의 환경에 따라 둘 이상의 스레드를 동시에 실행할 수 있다. 이것이 바로 멀티스레딩이다. 프로세스 구조 프로세스의 데이터와 명령어가 있는 영역은 Code(Text), Data, Stack, Heap이다. 💡각 프로세스는 별도의 공간(독립된 메모리)에서 실행되고 프로세스끼리는 자원의 공유를 하지 않는다. 그렇다보니, 프로세스 간의 자원을 공유하기 위해서는 별도의 통신이 필요하다. 스레드 구조 스레드는 Stack만 따로 할당받고, Code(Text), Data, Heap 영역은 프로세스의 자원을 공유한다. 💡자원을 공유하다보니, 시스템의 자원과 처리 비용이 멀티 프로세싱에 비해 적다. (통신의 부담X) 하지만 자원을 공유하고 있다 보니, 멀티 스레딩 환경에서 동기화의 문제가 발생할 수 있다. 1. GIL 이란? 1-1. GIL 의 정의 → GIL은 Global Interpreter Lock의 약어로, 여러개의 스레드 중 단 1개의 스레드에서만 파이썬 코드를 사용 할 수 있게끔 잠금을 거는 것을 의미한다. 쉽게 말해서, 하나의 스레드만 파이썬 인터프레터를 제어할 수 있도록 하는 것을 의미한다. 더 쉽게말해서, 파이썬 프로그램은 오직 단 하나의 스레드에서만 실행된다. 이러한 GIL 때문에, 파이썬 멀티스레드 프로그래밍에서는 멀티스레드가 싱글스레드처럼 동작하는 성능 병목 현상을 발견할 수 있다. 1-2. GIL의 등장 배경 → GIL의 등장(설계)배경은 간단하게 말해서 메모리 안전성을 보장하기 위함이다. 파이썬의 메모리 관리 방법 중 하나로 레퍼런스 카운트(Reference Counts)가 있다. 레퍼런스 카운트 ? 레퍼런스 카운트란, 파이썬에서 생성된 객체가 객체를 가리키는 참조의 수를 추적하는 참조 카운트 변수를 가진다는 것을 의미한다. 즉, 레퍼런스 카운트 전략은 파이썬의 모든 객체에 카운트를 포함하고, 이 카운트는 객체가 참조될 때 증가하고, 참조가 삭제될 때 감소시키는 방식으로 작동된다. 이때 카운터가 0이 되면 가비지 컬렉터가 해당 객체를 메모리에서 삭제 시킨다. 이 레퍼런스 카운트 변수가 멀티 스레드 환경에서 두 스레드가 동시에 값을 늘리거나 동시에 값을 줄여버리는 Race Condition(경쟁 상태)이 발생할 수 있는 여지가 있다. 문제는, 이러한 상황이 발생하면 메모리의 누수가 발생하거나 객체의 대한 참조가 남아있는 데에도 메모리를 잘못 해제해버릴 수 있다. 아 !! 파이썬의 GIL은 레퍼런스 카운트에 대한 Race Condition을 미리 방지하기 위해 도입 되었구나 ! 멀티 스레딩 환경에서 동기화의 문제를 미리 방지하여 메모리 안정성을 보장하기 위한 디자인 이구나 !! 즉, 메모리를 취하고 성능을 잃는 것이다. 2. 싱글 스레드 vs 멀티 스레드 ❓그렇다면, Python언어로 멀티 스레드 프로그래밍은 아예 불가능할까? → No ! 가능하다. threading 모듈을 활용하면 된다. ❓오잉, 멀티 스레드 프로그래밍이 가능하다면 무조건 멀티 스레드를 이용해야하는 거 아닌가 ??! → No ! 어떤 작업을 하느냐에 따라 다르다. 아래는 CPU Bound와 I/O Bound를 표현하기 위해 임의로 작성한 코드이다. CPU Bound Program CPU 연산량이 많은 프로그램을 의미한다. I/O Bound Program 데이터 베이스 쿼리, 파일 입출력, 네트워크 통신 등과 같은 입출력 작업이 많은 프로그램을 의미한다. ❗해당 예시에서는, I/O작업을 한다고 가정하겠다. I/O작업 대기시간의 예시로 time.sleep(1) 함수를 이용하여 물리적으로 1초를 대기하도록 하겠다. (입출력 하는 시간) ❓time.sleep()은 I/O bound 작업이 아닌데요 ?!!! → 맞다. 둘 다 아니다. 아래에서 설명하겠다. 2-1. CPU Bound Program 위/아래 프로그램 둘 다, 입력 받은 수를 1씩 감소시켜 0까지 도달하게 하는 프로그램이다. 처음부터 끝까지 CPU연산으로 이뤄지니 CPU Bound 프로그램이라고 할 수 있다. 이 두 프로그램의 시간을 각각 측정해보면 다음과 같다. 싱글 스레드 = 26.54809초 멀티 스레드 = 26.65582초 연산이 매우 간단하여, 근소한 차이지만 그래도 싱글 스레드의 속도가 빠르다. 2-2. I/O Bound Program 해당 프로그램은 I/O Bound 프로그램의 예시로 위의 코드와 같은 코드 이지만, 함수 중간중간 time.sleep을 주어 I/O작업을 하는것으로 가정했다. 측정한 결과는 다음과 같다. (반복 작업이 많아 COUNT를 줄였다.) 싱글 스레드 = 10.93979초 멀티 스레드 = 5.02122초 CPU 작업에서는 아주 근소한 차이로 싱글스레드 작업이 더 빨랐는데, 이번에는 멀티 스레드가 더욱 빠르게 작업이 끝난걸 볼 수 있다. 게다가 차이도 꽤나 난다 ! ❓왜 이럴까 ??? → 이건 파이썬 인터프리터에서, I/O작업을 맞이할 때(다른 하드웨어 장치에 의존하는 작업)에 GIL을 해제하기 때문이다.(스레드 전환 가능) 잘 와닿지가 않는다. 한번 눈으로 확인해보자. 조금은 무식한 방법이지만, 눈으로 확인하고 싶기에 I/O Bound 코드에 현재 스레드를 print하는 코드를 추가해보았다. Single Thread 중간 체크 지점 0 - 현재 스레드: MainThread 중간 체크 지점 1 - 현재 스레드: MainThread 중간 체크 지점 2 - 현재 스레드: MainThread 중간 체크 지점 3 - 현재 스레드: MainThread 중간 체크 지점 4 - 현재 스레드: MainThread 중간 체크 지점 5 - 현재 스레드: MainThread 중간 체크 지점 6 - 현재 스레드: MainThread 중간 체크 지점 7 - 현재 스레드: MainThread 중간 체크 지점 8 - 현재 스레드: MainThread 중간 체크 지점 9 - 현재 스레드: MainThread 중간 체크 지점 10 - 현재 스레드: MainThread 1st Working : 5.43227 중간 체크 지점 0 - 현재 스레드: MainThread 중간 체크 지점 1 - 현재 스레드: MainThread 중간 체크 지점 2 - 현재 스레드: MainThread 중간 체크 지점 3 - 현재 스레드: MainThread 중간 체크 지점 4 - 현재 스레드: MainThread 중간 체크 지점 5 - 현재 스레드: MainThread 중간 체크 지점 6 - 현재 스레드: MainThread 중간 체크 지점 7 - 현재 스레드: MainThread 중간 체크 지점 8 - 현재 스레드: MainThread 중간 체크 지점 9 - 현재 스레드: MainThread 중간 체크 지점 10 - 현재 스레드: MainThread 2nd Working : 5.50752 Multi Thread 중간 체크 지점 0 - 현재 스레드: Thread-1 중간 체크 지점 1 - 현재 스레드: Thread-1 중간 체크 지점 0 - 현재 스레드: Thread-2 중간 체크 지점 1 - 현재 스레드: Thread-2 중간 체크 지점 2 - 현재 스레드: Thread-1 중간 체크 지점 3 - 현재 스레드: Thread-1 중간 체크 지점 2 - 현재 스레드: Thread-2 중간 체크 지점 3 - 현재 스레드: Thread-2 중간 체크 지점 4 - 현재 스레드: Thread-1 중간 체크 지점 5 - 현재 스레드: Thread-1 중간 체크 지점 4 - 현재 스레드: Thread-2 중간 체크 지점 5 - 현재 스레드: Thread-2 중간 체크 지점 6 - 현재 스레드: Thread-1 중간 체크 지점 7 - 현재 스레드: Thread-1 중간 체크 지점 6 - 현재 스레드: Thread-2 중간 체크 지점 7 - 현재 스레드: Thread-2 중간 체크 지점 8 - 현재 스레드: Thread-1 중간 체크 지점 9 - 현재 스레드: Thread-1 중간 체크 지점 8 - 현재 스레드: Thread-2 중간 체크 지점 9 - 현재 스레드: Thread-2 중간 체크 지점 10 - 현재 스레드: Thread-1 중간 체크 지점 10 - 현재 스레드: Thread-2 Multi Working : 5.02122 싱글 스레드는 곁눈질로만 훑어봐도 대충 어떻게 흘러갈지 예상이간다. 멀티 스레드는 뭔가 감이 잘 안온다. 해당 결과 한 눈에 볼수 있도록 흐름도를 만들어보았다. 싱글 스레드 흐름도 먼저 싱글스레드의 흐름도이다. 예상대로 메인스레드 단일로 작업이 수행되고, 2번째 작업은 1번째 작업이 끝난 뒤에야 작업을 시작한다. 멀티 스레드 흐름도 그 다음으로, 멀티스레드의 흐름도이다. 빨간색 선이 I/O (예제 코드 Sleep)이고, 해당 작업이 진행되는 시점에 스레드의 전환 (GIL 해제)이 이뤄져서 Thread-2가 작업을 수행한다. ❓time.sleep()은 I/O Bound가 아니라메 !!! time.sleep()은 I/O작업이 아니다. 그럼에도 왜 I/O라고 가정한 시점에 스레드가 변경이 될까?? 그걸 알아보기 위해서는 Python2와 Python3의 GIL이 해제되는(스레드가 전환되는) 매커니즘에 대한 이해가 필요하다. 2-3. Python2 / Python3 GIL 수행 매커니즘 비교 파이썬2 버전의 GIL 메커니즘 파이썬 2버전의 GIL 수행 매커니즘이다. 제어권을 가지고 있는 스레드에서 I/O작업이 발생하기 전까지 GIL을 해제하지 않고, 그 말은 즉슨 다른 스레드들은 무한정 대기를 해야한다는 뜻이다. 그렇기에, 코드 수행에서의 병목현상이 많이 발생하였고, 이 점은 파이썬 3버전에서 부터 개선되었다. 파이썬3 버전의 GIL 메커니즘 파이썬 2버전의 이러한 단점을 개선하기 위하여 파이썬 3버전에서는 멀티스레드 환경에서 제어권을 가진 스레드에 고정 5ms의 기본 실행 시간이 할당된다. (5ms가 지나면 GIL 해제 - 스레드 전환) 우측 사진은 예제 코드에서 I/O 작업이라고 가정한 sleep을 제거한 코드이다. 오로지 CPU Bound 코드만이 존재하는데에도, 스레드가 전환되는 것을 확인할 수 있다. 위에서 보여준 흐름도에서 sleep하는 시점에 스레드 전환이 이뤄진것도, countdown 함수를 5ms안에 수행하고 1초를 sleep하면서 5ms가 지나 스레드가 전환된 것이다. ❓그럼 단점도 개선되었으니, 멀티 스레드가 좋은거 아니야? 위에 sleep이 없는 코드의 결과에서 볼 수 있듯이, 멀티스레드 환경이 시간이 더 오래 걸렸다. I/O환경에서의 어쩔 수 없는 대기 시간에 스레드를 전환해서 다른 일을 수행한다면 당연히 효율적이겠지만, 내부 로직만 수행되는 CPU Bound 위주의 코드에서는 5ms의 기본 시간 뒤, 스레드를 전환하는 과정에서 컨텍스트 스위칭으로 인한 비용 발생으로 오히려 동작시간이 증가했다. 3. 결론 파이썬은 GIL라는 제약 때문에, 단 한개의 스레드에서만 코드가 수행된다. GIL은 메모리의 안정성을 위해 도입되었다. 몇몇 개발자들은 GIL 제약이 너무 가혹 하다며 혀를 찬다고 한다. 그럼에도 개발된 Thread 모듈 덕분에 멀티 스레드 환경에서의 동작 수행이 가능하다. 하지만, “병렬성”이라는 알맹이가 빠진 “동시성”만 지닌…. I/O Bound 위주의 코드에서는 멀티 스레드가 유리하다. CPU Bound 위주의 코드에서는 싱글 스레드가 유리하다. 과거 (파이썬 2버전)에는 스레드의 작업이 완료되거나 I/O로 인한 GIL해제가 되지 않았다면 다른 스레드들은 무한정 대기를 해야했다. 파이썬 3버전에서 5ms뒤에 스레드 전환으로 개선되었다. (기본시간. 조정 가능) 작년 하반기 GIL 제약을 없애버리는 작업에 착수 했다고 파이썬 개발 팀이 발표했다. 출처 https://docs.python.org/ko/3/c-api/memory.html https://velog.io/@jaebig/python-동시성-관리-1-프로세스Process와-스레드Thread https://tibetsandfox.tistory.com/43?category=885924 https://velog.io/@jaebig/python-동시성-관리-3-코루틴Coroutine#python-동시성-관리를-이해하기-위하여-알아야-할-것들 https://bloofer.net/114
김원준
❤️
2
TDD(Test-Driven Development)
안녕하세요, 오늘은 TDD(Test-Driven Development)에 대해 이야기하려 합니다. TDD 소프트웨어 개발 방법론 중 하나로, 개발 과정에서 테스트를 우선하여 작성하고 이를 통과시키는 것에 초점을 두는 방법론입니다. 코드를 작성하기 이전에 테스트 케이스를 작성하고, 이를 통과하기 위한 그에 맞는 기능을 작성하는 작업을 반복하여 개발합니다. TDD의 장점과 한계 TDD의 장점: 품질 향상: 개발자는 코드의 동작을 확실히 이해하고 테스트 케이스를 통해 코드의 정확성을 검증할 수 있어, 더 견고하고 안정적인 코드를 작성할 수 있습니다. 리팩토링 지원: 코드를 작은 단위로 분리하고 테스트 가능한 형태로 작성하여 코드의 구조와 설계를 개선하기 쉽게 합니다. 빠른 피드백: 작은 단위의 테스트를 빠르게 실행하고 결과를 확인하여 버그를 빠르게 발견하고 수정할 수 있으며, 코드 변경에 대한 피드백을 신속하게 받을 수 있습니다. 협업 강화: 테스트 코드가 개발 프로세스의 일부로 문서화되어 있어 다른 개발자들과의 협업을 용이하게 하며, 코드의 동작을 이해하고 검증하는 데 도움이 됩니다. TDD의 한계: 시간과 노력: 테스트 코드를 작성하기 위해 추가적인 시간과 노력이 필요하며, 개발 시간이 늘어날 수 있습니다. 설계에 대한 이해: 테스트 케이스를 작성하기 위해 개발자는 코드의 설계에 대한 깊은 이해가 필요하며, 이를 갖추지 않으면 테스트 케이스가 미흡해질 수 있습니다. 복잡한 시나리오의 테스트: 복잡한 시나리오나 UI, 성능 테스트 등은 TDD로 테스트하기 어려울 수 있습니다. 변동이 많은 요구사항: 요구사항이 자주 변경되는 경우, 테스트 케이스를 계속 수정해야 하는 상황이 발생할 수 있습니다. 출처: https://semaphoreci.com/wp-content/uploads/2022/02/tdd-vs-waterfall.webp 이러한 장점과 한계로 인해 TDD는 초기에는 추가 비용이 들 수 있지만, 시간이 지남에 따라 비용을 절감할 수 있는 특징을 지녔습니다. TDD의 사이클 Lifecycle of the Test-Driven Development method 출처: https://ko.wikipedia.org/wiki/테스트_주도_개발 Write Test: 기능을 검증할 테스트 케이스를 작성 Test Fails: 작성한 테스트 케이스를 실행하여 실패하는 것을 확인 Write Code: 테스트를 통과할 수 있는 코드를 작성 Test Passes: 작성한 코드가 테스트를 통과하는지 확인 Refactor: 코드를 개선하고 리팩토링하는 단계 예시코드 유효한 이메일을 검증하는 기능의 개발을 가정하고 프로세스를 진행해보겠습니다. Write Test : 테스트 코드 작성 Test Fails : 실패하는 테스트 실행 위 테스트 코드에서는 **validate_email** 함수가 구현되지 않았으므로 모든 테스트는 실패 Write Code: 코드 작성 주어진 이메일이 유효한지 여부를 확인하는 validate_email 함수를 작성 Test Passes: 테스트 통과 Refactor: 리펙토링 TDD를 실제 적용하기 위한 난관들 실제 적용 사례에서 얘기하는 문제들 팀 내 새로운 개발 방법의 도입의 어려움 일정문제 생산성 문제 테스트 코드 작성의 어려움 미숙한 TDD 도입 미숙한 TDD의 도입은 아래 그림과 같이 개발 초기에 들인 노력에 비해 효과를 얻을 수 없었습니다. 출처: https://semaphoreci.com/wp-content/uploads/2022/02/good-vs-bad-tdd.webp 효과 TDD를 도입한 기업들은 코드의 품질 향상과 버그의 조기 발견, 개발자 간의 협업 강화 등의 이점을 봤습니다. 또한 요구사항 변경에 유연하게 대응할 수 있는 더 민첩한 개발 프로세스를 구축할 수 있었습니다. 결론 위와 같은 어려움으로 인해서 그런지 모르겠지만 찾아본 실제 적용한 사례들은 주로 테스트 범위를 한정시켜 TDD를 적용시켰습니다. 또한, 카카오뱅크 TDD 사례에서는 기존 코드를 바탕으로 테스트 코드를 새로 작성하며, TDD 접근 방식으로 테스트 코드를 작성하는게 얼마나 어려운지 보여주었습니다. 공부를 하며 TDD는 결과물의 높은 코드 품질을 유지하는 데 매력적이지만, 도입을 실제 적용하기에는 많은 문제들을 헤쳐나가야한다는 점을 느낄 수 있었습니다. 그래서 다음 시간에는 테스트 코드를 작성하는 법에 대해서 한번 공부해보려고합니다. 참고자료 이론 https://adjh54.tistory.com/305#google_vignette https://semaphoreci.com/blog/economics-of-tdd https://manorgass.tistory.com/63 https://blog.barogo.io/개발인턴-테스트-방식에-대한-적절성-및-고민-with-tdd-6e19d3fb32bd https://inpa.tistory.com/entry/QA-📚-TDD-방법론-테스트-주도-개발 https://tech1.tistory.com/89#TDD(Test-Driven_Development)란? 실제 TDD 적용 사례 https://tech.kakaopay.com/post/implementing-tdd-in-practical-applications/#현실에서-tdd를-해보자 https://brunch.co.kr/@tilltue/69 https://oliveyoung.tech/blog/2023-10-30/wcare-tdd-development/
Lighthouse
파이썬의 동시성 관리 : 코루틴(Corutine) 上
0. 들어가기 앞서 지난 시간에는 파이썬의 GIL 제약과 그 제약으로 인해 “찐”효율을 내지 못하는 멀티 스레드 프로그래밍에 대해서 알아보았다. 이번 시간에는 파이썬 비동기의 핵심 키워드 네이티브 코루틴인 Asyncio, async, await를 이해하기 전 이것들의 근간이라 불리는 코루틴(Corutine)에 대해서 알아보자. 들어가기 앞서, 복습 차원에서 지난 시간 내용을 간략하게 정리하자 1. 제네레이터 1.1. 제네레이터 제네레이터는 쉽게 말해서, 여러개의 데이터를 미리 만들어 놓지 않고 필요한 때마다 즉석에서 하나씩 만들어낼 수 있는 객체를 의미한다. 일반적인 함수와 달리 상태를 유지할 수 있다. 즉, 제네레이터는 yield 표현식을 사용하여 값을 반환하고, 다음 호출 시 마지막으로 실행된 yield 표현식 이후부터 실행을 재개한다. 일반함수는 return을 만나면 실행이 끝나버린다. 하지만 제네레이터는 yield 구문에서 “일시정지”의 상태로 값을 외부로 내보낸다. 그 이후에 필요할 때 다시 실행 흐름을 이어나갈 수 있다. 함수 내부에서 사용된 지역 변수등이 메모리에 그대로 유지되어 있기 때문이다. 아래 코드를 살펴보자. 함수 return_abc()는, 알파벳을 1초마다 하나하나 리스트에 적재하는 코드이다. print를 찍어본다면 어떻게 될까? 너무 당연한 결과이다. 그렇다면 해당 함수를 for loop에 돌려보면 어떻게 될까? 이 결과 역시 너무나도 쉽게 예상할 수 있다. 여기서 3초라는 시간을 잘 기억해주길 바란다. 위에서 제네레이터는 데이터를 미리 만들어두지 않고, 필요할 때마다 하나씩 만들어내는 객체를 뜻한다 했다. 이것도 코드를 통해 알아보자. 뭔가 위의 코드랑 별로 달라진게 없어보인다. print를 찍어보자. !! 예상했던 것과는 달리 제네레이터가 출력 되었다 !! 위에서 언급했던 것처럼 제네레이터는 “필요할 때마다” “하나씩” 만들어 낸다고 했으니, 한번 for문을 통해서 “하나씩” 값을 받아와 보자. return_abc() 함수와 비교하였을때, 시간상으로는 똑같이 3초+@가 소요 되었다. 하지만 값을 수령하는 방식에서 차이가 발생했다. return_abc는 한번에 전부. yield_abc는 한개씩. 예제코드처럼, ABC 3개의 알파벳이 아닌, 수천 수만개의 알파벳이라면? yield_abc는 수천~수만초의 시간이 흐르기 전에 값을 계속해서 수령해서 프로세스가 진행 될 테고, (A 수령 → 작업 → B수령 → 작업 → C수령 → 작업 ………) return_abc는 수천~수만초의 시간이 흐를때 동안 아무것도 하지 못한체, 하염없이 return_abc의 리턴값만 기다릴 것이다. (대기…………………………..→ 총 수령 → 총 작업) 또, 메모리 효율 측면에서도 말할게 생기는데 return 키워드를 사용할 때는 모든 결과 값을 메모리에 올려놓아야 하는 반면에, yield 키워드를 사용할 때는 결과 값을 하나하나 메모리에 올려놓기 때문에 메모리 측면에서도 효율 적이다. ( 특히 한번에 메모리에 가득 올리기에 부담이 가는 대용량 파일을 읽을때 효율적일 것 같다 !) 그러한 특성들 때문에 제네레이터는 흔히 게으른 반복자(lazy iterator)라고도 불린다. 이러한 게으른 특성을 잘 활용한다면 효율적인 작업이 가능하다 ! 얼떨결에, 장점까지 말해버렸다. 1.2. yield ? 제네레이터도 이해하기 힘든데, 생소한 yield가 등장해버렸다. 어디서 본적이 있지만, 스쳐지나간 적이 많은 키워드라고 생각한다. 보통의 함수는 호출되면 그 내부의 모든 코드를 실행하고 값을 반환한 후 종료되지만, yield를 사용하면 함수는 값을 반환한 후에도 종료되지 않고 일시적으로 멈춘다. 그리고 다음 번에 다시 호출되면 멈췄던 그 지점 코드부터 실행을 재개한다. ⚠️❗⚠️❗⚠️❗⚠️ 선생님 이해가 안돼요❗⚠️❗⚠️❗⚠️❗⚠️❗ 이것만 기억하자 !! yield 키워드는, 코루틴에서 값의 “전달(함수 재개)”과 “반환(함수 중지)”을 모두 담당한다. 값 전달 (input) - 함수 재개 yield를 통해 값을 할당 받는다. 중단되었던 함수라면, 중단됐던 yield의 다음 코드부터 재개 된다. 이때, input값은 일전에 중단되었던 yield 부분에서 할당된다. 값 반환 (output) yield를 통해 값을 반환한다. 함수가 진행되면서, yield를 만나면 함수를 중단하고 값을 반환한다. 즉 yield는 함수가 일시중지되는 지점을 결정하고, 다시 재개되는 지점을 결정하는 중요한 역할을 한다. 2. 코루틴 (Corutine) 2.1. 코루틴 이란? 코루틴(Corutine)이란, Cooperative + Routine의 의미로, “상호 협력하는 루틴”이라고 할 수 있다. 파이썬의 asyncio / async와 await 키워드가 바로 코루틴을 기반을 둔 비동기 프로그래밍 기법이다. async - 코루틴 함수 선언. await - 대기하면서, 다른 루틴이 실행될 수 있도록. 서브루틴과 달리 현재 상태값을 저장하고 메인루틴으로 돌아간 뒤 나중에 호출하게 되면 저장했던 상태를 꺼내서 다음 상태를 진행할 수 있는 함수(루틴) ❓상호 협력 직관적인 이해를 위해, 코드와 그림을 통해 이해해보자 ! 팀원들에게 아침, 점심, 저녁 인사를 하는 너무나도 간단한 코드이다. start_normal_greeting함수 안에서 normal_hello 함수를 호출하고, normal_hello함수가 끝남과 동시에, normal_hello 함수에 들어있던 모든 것은 사라진다. 이를 보통 메인 루틴에서 서브 루틴을 호출하고, 서브루틴은 종료된다 라고 얘기한다. 아래 그림으로 간단하게 살펴보자. 2.1.1. 일반적인 루틴의 플로우 그림과 같이, 서브루틴은 메인루틴에 의해 호출 및 종료가 결정이되는 **“종속”**관계라고 할 수 있다. 하지만, 코루틴은 방식이 다르다. 위처럼 메인 루틴과 서브 루틴이 **“종속”**적인 관계가 아니라, 서로 **“대등”**한 관계이며, 특정 시점에 상대방의 코드를 실행한다. 아래 예시 코드를 보자. 뭔가 코드의 형태도 비슷하고, 출력 값 또한 일치한다 ..! 또 눈에 띄는것이, 아까 설명했던 yield가 등장한다 ! 그럼. 해당 코드의 출력 값은 어떻게 될까? 출력값 good morning good morningafternoon good morningafternoonevening 원하던 바가 아니다. 그럼 팀원들에게 제대로된 인사를 하기 위해서는 코드를 어떻게 수정해야할까? 메인 - 서브 루틴에서의 종속적인 관계와 달리, 코루틴에서는 coroutine_hello 함수가 실행-종료를 반복되는 것이 아니라, 계속해서 “대기”를 하게된다. 즉 print문에서 3번 호출된다 해서 3번 실행 - 3번종료가 아닌, 최초 실행 - 대기 (작업수행) - 종료 라는 것이다 ! 다시말해서, 함수의 호출과 종료가 한큐에 일어나는 서브루틴과 달리, 코루틴에서는 함수가 종료될 것 같은 시기에 대기를 하게되니, 다시 호출(사실은 재개)이 된다 하더라도, 변수값이 계속 유지되기 때문이다. 그림으로 보면 다음과 같다. 2.1.2. 코루틴의 플로우 이처럼 코루틴은 함수가 종료되지 않은 상태에서 메인 루틴의 코드를 실행하고, 다시 돌아와 코루틴의 코드를 실행한다. 함수의 코드를 실행하는 지점을 진입점(entry point)라고 하는데, 코루틴은 진입점이 여러개다. (yield) 이런 점에서 코루틴은 일반 루틴에 비해 메인 루틴과의 종속 관계가 아닌 대등한 관계이며, 그래서 상호 협력하는 관계라고 칭한다. 마치며 사실 이번 발표는, 처음 코루틴 발표를 계획했을 때의 30%분량도 채우지 못한 것 같다. 원래 목표는 코루틴에 대한 간단한 설명과 더불어 지난 시간에 발표한 멀티스레딩 프로그래밍과 예시코드로 직접적인 속도비교 및 분석 까지가 목표 였는데, 발표를 위한 공부를 이어가다보니 기반을 닦아 놓지 않으면 이도저도 안될 것 같아서 기초적인 원리에 중점을 둔 발표라고 생각한다. 이번 발표를 간단히 정리해보자면 딱 “코루틴의 개요” 정도일 것 같다. step1인 개요를 지났으니, 다음 시간에는 좀 더 딥다이브 하게 코루틴에 대해 살펴보고, 코루틴의 발전과정 / async/await로의 진화 과정을 설명 해볼까 한다. 출처 https://ko.wikipedia.org/wiki/코루틴 https://blog.humminglab.io/posts/python-coroutine-programming-1/ https://velog.io/@jaebig/python-동시성-관리-3-코루틴Coroutine https://velog.io/@kho5420/Python-coroutine-코루틴 https://tobuymacbookpro.tistory.com/6 https://www.daleseo.com/python-yield/ https://engineer-mole.tistory.com/64 https://teddylee777.github.io/python/python-async/
Lighthouse
FastAPI 특징 with Pydantic
이번 글에서는 python FastAPI의 특징과 FastAPI내에서 Pydantic을 사용한 코드를 확인해 보겠습니다. Fast API Fast API란? FastAPI는 Python 프레임워크 중 하나입니다. Python 프레임워크들 중 django, flask 와 같이 비교를 많이 하며, 빠른 속도로 인해 인기가 많아진 프레임워크입니다. FastAPI에서 제공하는 기능들을 간략히 보면 아래와 같습니다. API 문서 자동 생성 (Swagger와 ReDoc 스타일 동일) 의존성 주입 위주의 설계를 통한 DB 등에 대한 관리 편리 비동기 동작으로 빠른 성능 보장 (Starlette) Pydantic을 사용한 Validation 체크 뛰어난 공식문서 가이드 Python Framework 깃허브 스타 github star history 그래프를 보면 FastAPI(노란색)의 스타가 급격히 증가하는 것을 확인 할 수 있습니다. 그래프를 통해 FastAPI를 많이 사용한다는 의미는 될 수 없겠지만, 개발자들 사이에서 관심을 많이 갖고 있는것은 확인 할 수 있을것 같습니다. FastAPI의 특징 특징들을 Fast API 공식문서를 통해 자세하게 확인해 보겠습니다. 파이썬 3.8+ 버전의 Type hint를 사용하는 트랜디하고 높은 성능을 가진 파이썬 프레임워크 빠름: NodeJS 및 Go와 동등한 매우 높은 성능을 제공 실제 파이썬 기반의 프레임워크들을 비교한 내용을 확인해 보면 성능이 상위에 존재하는 것을 확인 할 수 있습니다. 빠른 코딩: 기능 개발 속도를 약 200%~300% 향상 버그 감소: 인간(개발자)이 유발한 오류의 약 40% 감소 직관적: 뛰어난 편집기 지원. 디버깅 시간이 줄어듭니다. 간단: 사용 및 학습이 용이하도록 설계되었습니다. 문서를 읽는 시간이 줄어듭니다. 짧게: 코드 중복을 최소화합니다. 버그 수를 줄입니다. 견고함: production-ready code를 얻을 수 있음. To write production-ready code in Python, it is important to understand the importance of code modularization, following PEP8 style guidelines, using meaningful variable, class, and function names, organizing your code, and writing thorough documentation. 표준 기반: API의 개방형 표준인 OpenAPI(이전의 Swagger)와 JSON Schema를 기반으로 합니다. Starlette & Pydantic Fast API는 빠른 속도와 코딩이 가능하고, 직관적이라고 합니다. 이런 특징을 갖게 된 이유는 Starlette 과 Pydantic 등을 사용한 결과이기도 합니다. Starlette Starlette에 대해 알기 전에 먼저 ASGI, WSGI에 대해 알아 보겠습니다. WSGI(Web Server Gateway Interface) WSGI는 파이썬 웹 응용 프로그램을 위한 것 웹서버와 파이썬으로 작성된 웹 응용 프로그램 간의 표준 인터페이스 gunicorn 기존의 동기(django, flask)로 작동되는 웹프레임워크들은 gunicorn을 많이 사용했습니다. ASGI(Asynchronous Server Gateway Interface) ASGI의 공식문서에서는 따르면, ASGI는 WSGI의 정신적 계승자로, 비동기 가능 Python 웹 서버, 프레임워크 및 애플리케이션 간의 표준 인터페이스를 제공하기 위한 것 WSGI가 동기 Python 앱에 대한 표준을 제공했다면 ASGI는 WSGI 이전 버전과의 호환성 구현과 여러 서버 및 애플리케이션 프레임워크를 통해 비동기 및 동기 앱 모두에 대한 표준을 제공합니다. 다시 Starlette으로 돌아가면, 공식 문서에서는 Python에서 비동기 웹 서비스를 구축하는 데 이상적인 경량 ASGI 프레임워크/툴킷으로 설명 합니다. 그리고 FastAPI는 이 Starlette을 기반으로 개발이 되었고, 그로 인해 비동기 동작이 가능한 서버를 구현합니다. 아래의 이미지 처럼 FastAPI앞에 ASGI의 하나인 uvicorn을 넣어서 비동기로 서버를 운영합니다. Pydantic Pydantic은 파이썬의 Type annotation(type hint)을 활용하여 data validataion(검증)과 세팅을 관리해 주는 파이썬 라이브러리입니다. FastAPI에서 Pydantic이 하는 역할은 다음과 같습니다. API 문서 자동화 입출력 항목의 갯수와 타입을 설정 입출력 항목의 필수값 체크 입출력 항목의 데이터 검증 Pydantic 장점 FastAPI에서 Pydantic을 사용하는 이점은 다음과 같습니다. 데이터 검증 및 직렬화 최적화 : Pydantic은 데이터 검증 및 직렬화(데이터 구조를 문자열 형태로 변환) 과정을 효율적으로 처리합니다. 이는 FastAPI가 요청을 빠르게 분석하고 응답 데이터를 신속하게 생성하는데 도움을 줍니다. 타입 힌트와 통합 : Pydantic은 Python의 타입 힌트와 밀접하게 통합되어 있어 명확한 타입 정의를 사용할 수 있게 합니다. 이를 통해 런타임 오류를 줄이고 성능을 개선합니다. 오류 처리 : Pydantic은 유효성 검증을 통해 발생할 수 있는 오류를 잡아내고, 에러 메시지로 반환하여 안정적인 성능을 유지하는데 기여합니다. 코드의 간결성과 유지보수성 : Pydantic을 사용하면 데이터 모델을 쉽게 유지보수 할 수 있습니다. Pydantic - 적용 예제 코드 Pydantic - 데이터 검증 예제 코드 update를 하는 API가 있을 때, request body 값에 들어가야하는 내용을 Pydantic을 사용하여 데이터 스키마를 정의합니다. Type hint를 활용해서 데이터 속성의 타입을 정의 할 수 있습니다. FastAPI에서 제공하는 OpenAPI(swagger)로 확인을 해보면 path parameter, query parameter, request body를 확인 할 수 있고, 테스트가 가능합니다. request body 값으로 미리 설정한 Pydantic에 맞게 실행을 하게 된다면 정상적으로 200 을 반환합니다. 하지만 검증에 틀리는 경우에는 다음과 같습니다. 마무리 이번 세션을 준비하면서 Fast API에 대해 공부를 했습니다. 공식 가이드 문서가 잘 되어 있고, 관련된 기술 블로그들도 생각보다 많아서 참고하기에 좋았습니다. 참고 사이트 및 문서 https://fastapi.tiangolo.com/ https://www.starlette.io/ https://asgi.readthedocs.io/en/latest/introduction.html https://tech.kakaopay.com/post/image-processing-server-framework/#user-content-fn-2 https://dingrr.com/blog/post/python-웹프레임워크-끝판왕-가리기-django-flask-fastapi-sanic https://medium.com/svelte-seoul/서버-web-server-cgi-was-wsgi-에-대한-이해-2ab0f9bfabd4 https://breezymind.com/start-asgi-framework/
donggyun_woo
👍🟩😘😀👍🏻
6
[1] - Sync 와 Async 그리고 Blocking과 NonBlocking
0. 개요 아무것도 모르는 대학생 시절에, 학부 인턴을한 적이 있다. 그때 팀장님이 신입 면접을 보고 오신 뒤, 나에게 질문을 하신 적이 있다. “oo아 동기와 비동기 차이를 설명해 봐” 동기 - “하나하나 순차적으로 실행하는 것 !” 비동기 - “동시에 실행되는 것 !” 이라고 대답한 기억이 있다. 아마 이렇게 대답한 나는 그 당시에 동기 / 비동기를 아래 사진과 같이 이해하고 있었던 것 같다. 내가 이해한 "동기" 내가 이해한 "비동기" 얼핏 보기엔 맞는 대답이기도 하다. 하지만 지금 와서 생각해 보면 “하나하나 순차적으로 실행하는 것 !”의 대답은, Blocking Sync에 대한 설명일 수도 있고, Blocking Async에 대한 설명일 수도 있다. 또, “동시에 실행되는 것 !” 의 대답은, NonBlocking Sync일 수도 있고 NonBlocking Async일 수도 있다. 물론, 이론적으론 그렇다. 해당 개념을 잘 모르는 사람에게는, Sync와 Async의 단어 자체는 익숙할 수 있어도, Blocking과 NonBlocking이 앞에 붙는 순간 머리가 아파올 수 있다. 이번 시간에 Blocking / NonBlocking과 Sync / Async에 대해서 간단하게 살펴보자. 들어가기에 앞서 ! 제어권 • 제어권은 자신(함수)의 코드를 실행할 권리 같은 것이다. 제어권을 가진 함수는 자신의 코드를 끝까지 실행한 후, 자신을 호출한 함수에게 돌려준다. 종료 호출 • A 함수에서 B 함수를 호출했을 때, A 함수가 B 함수의 결과 값을 기다리느냐의 여부를 의미한다. 용어를 숙지하자 ! 1. Blocking? Sync? 그게 뭐야 ?? 🤔 Sync 와 Async. 또 Blocking과 NonBlocking은 “관점”에 차이에 있다. ✅ Blocking / NonBlocking은 호출한 함수가 호출된 함수에게 제어권을 주느냐의 관점 ✅ Sync / Async는 호출된 함수의 종료 호출을 호출한 함수가 처리하는지, 호출된 함수가 처리하는지의 관점 이렇게만 봐서는, 이해가 안 될 것 같다. 나라도 그럴 것이다. 2. Blocking과 NonBlocking 2-1. Blocking → A함수가 B함수를 호출할 때, B함수가 자신의 작업이 종료되기 전까지 A함수에게 제어권을 돌려주지 않는 것 A함수가 B 함수를 호출하면, 제어권을 B에게 넘긴다. 호출된 B함수는 제어권을 갖고 있기에 함수를 실행한다. 이때! A 함수는 제어권이 없기때문에 (B에게 넘겨주었기 때문에) 함수 실행을 멈춘다. B함수가 완료되면, A함수에게 제어권을 돌려준다. 잠시 중단되었던 A함수는 다시 함수를 이어나간다. 2-2. NonBlocking → A함수가 B함수를 호출할 때, B함수가 제어권을 바로 A함수에게 넘겨주면서, A함수가 다른 일을 할 수 있도록 하는 것 A함수가 B함수를 호출하여 실행시킨다. 이때! 제어권은 계속 A가 가지고 있기 때문에, 호출한 이후에도 A는 자신의 코드를 계속 실행시킨다. 3. Sync와 Async 3-1. Sync 플로우가 순차적으로 이뤄져야 함. A함수가 B함수를 호출 할 때, B함수의 결과값이 나왔는지 A함수가 계속해서 관여하는 것. B함수의 종료 여부를 계속해서 신경 쓴다. ✔️ 결과값 & 제어권의 반환이 동시에 이뤄짐 3-2. Async 플로우가 순서에 영향을 받지 않음. A함수가 B함수를 호출 할 때, B함수의 결과를 B함수가 처리하는 것. (Callback 이용) B함수의 종료 여부를 신경 쓰지 않는다. ✔️ 결과값 & 제어권의 반환이 동시에 이뤄지지 않음 4. 크로스오버 조합 4-1. Blocking - Sync 한 줄 요약 : 가장 보편적으로 이해하고 있는 동기 - 기다릴 가치가 있네 ! A 함수가 B 함수를 호출했을 때, A 함수는 작업을 중단한다. (제어권을 넘겨줬기에 !!) - Blocking 호출된 함수B의 리턴 값을 A함수가 필요로 한다. (함수의 종료와 결과 값 반환을 신경 쓴다.) + 제어권의 반환과 결과 값의 반환이 일치한다. - Sync 🤔언제 쓸까? → 다른 작업의 결과가 자신의 작업에 영향을 주는. 즉, 순차적인 의존성이 있는 작업을 처리할 때. 4-2. NonBlocking - Sync 한 줄 요약 : 동기이지만, 동시에 실행이 가능하다 !! (feat. 컨텍스트 스위칭) A 함수가 B 함수를 호출해도, A 함수는 작업을 계속 이어나간다. - NonBlocking 호출된 함수 B의 종료를 A가 관리한다. + 결과값의 반환과 제어권의 반환이 일치한다. - Sync 결과값의 반환과 제어권의 반환이 일치한다. “응 아직 안 끝남” 역시 결과값 !!! (안끝났다는 결과값) 🤔언제 쓸까? → 브라우저에서 프로그램을 다운로드 할 때 !! 브라우저에서 다운로드 버튼을 누르면 백그라운드에서 다운로드 진행 다운로드 중에 브라우저에서 다른 작업 가능 ! (NonBlocking) 다른작업 중에도, 브라우저는 계속해서 다운로드 상태 확인 (로딩%라든지.. 완료 되었는지.. 실패했는지 .. 등등) 다운로드가 완료 되어야만 바로 다음 작업이 수행됨! (3&4 Sync) 4-3. NonBlocking - Async 한 줄 요약 : 가장 보편적으로 이해하고 있는 비동기 !! - 각개전투 ! A 함수가 B 함수를 호출해도, A 함수는 작업을 계속 이어나간다. - NonBlocking B함수의 종료를 A함수가 신경 쓰지 않음(A프로세스에 B의 리턴값이 중요하지 않다.) + 결과값의 반환과 제어권의 반환이 일치하지 않는다. - Async 🤔언제 쓸까? → 호출하는 함수에 종료 여부 / 결과 값에 연연하지 않는 & 파일/네트워크 I/O 등 동시 작업을 필요로 하는 프로세스에서 ! 4-4. Blocking - Async 한 줄 요약 : 비효율의 끝판왕 !! - 전설의 포켓몬 A 함수가 B 함수를 호출했을 때, A 함수는 작업을 중단한다. - Blocking B함수의 종료를 A함수가 신경 쓰지 않음(A프로세스에 B의 리턴 값이 중요하지 않다.) . + 결과값의 반환과 제어권의 반환이 일치하지 않는다. - Async ✔️B함수가 끝나기를 기껏 기다려 놓고, 결과값 역시 사용하지 않아버리는 ?!!?! 🤔언제쓸까? → 왜 쓸까? 사용하는 경우는 대부분 개발자의 실수인 anti-pattern인 경우라고 한다. node & mysql 간의 통신에서 사용된다고 하니, 관심이 있다면 한번 찾아보는 걸 권한다. 5. NonBlocking Sync vs NonBlocking Async 가만 살펴보니, NonBlocking Sync와 NonBlocking Async는 다른 작업이 진행 중이더라도(함수가 호출 중 이더라도) 중단하지 않고 프로세스를 이어나갈 수 있다. 그렇다면 여기서 한 가지 의문이 든다. “우리의 목표는 다른 함수를 호출해도 중단 없이 플로우를 이어나가는 것 아닌가? 복잡하게 Async로 코딩할 필요 없는 거 아니야? ” 사실 이번 발표를 준비하면서 끊임없이 들었던 의문이기도 하다. 그렇다면 NonBlocking Sync와 NonBlocking Async의 결정적인 차이. 다시 말해 무엇을 위해서 Sync / Async를 구분지어 사용&개발 할까? 쉬운 이해를 위해 예를 들어 설명해보겠다. NonBlocking - Sync 1️⃣프로젝트를 맡고있는 1️⃣팀은 팀장이 업무 A, B, C를 사원 a, b, c에게 시키려고 한다. 이때 해당 업무는 업무 특성상 A업무가 완료되어야 그 다음 업무인 B로 순차적으로 이어나갈 수 있는 상황이다. 👨🏻 팀장 : 사원 a님, A업무 처리해주세요. (👨🏻 팀장님은 다른 업무 중 …) 👦🏻 사원a : 네, 알겠습니다 ! (A 처리 중..) 👨🏻 팀장 : a님 완료했나요? 👦🏻 사원a : 아직 완료 못했습니다 ! 👨🏻 팀장 : a님 완료했나요? 👦🏻 사원a : 완료했습니다 !! 👨🏻 팀장 : 감사합니다. 곧 바로 b님, B업무 처리 부탁드릴게요. (👨🏻 팀장님은 다른 업무 중 …) 👨🏻‍🦰 사원b : 네, 알겠습니다 !! (B 처리 중..) 👨🏻 팀장 : b님 B업무 완료했나요? 이후 생략... NonBlocking - Async 2️⃣프로젝트를 맡고 있는 2️⃣팀은 팀장이 업무 A, B, C를 사원 a, b, c에게 시키려고 한다. 이때 해당 업무A, B, C는 업무 간의 영향이 없다. 👨🏻 팀장 : 사원 a님, A업무 처리해주세요. 👨🏻 팀장 : 사원 b님, B업무 처리해주세요. 👨🏻 팀장 : 사원 c님, C업무 처리해주세요. (👨🏻 팀장님은 다른 업무 중 …) 👩🏻‍🦰 사원c : 팀장님, C업무 완료했습니다. 👦🏻 사원a : 팀장님, A업무 완료했습니다. 👨🏻‍🦰 사원b : 팀장님, B업무 완료했습니다. 1번 케이스를 먼저 살펴보자. 팀장님 (제어권을 가진 main 함수)이 사원들에게 업무를 지시하는 상황이다. 팀장님은 업무를 지시하고 다른 업무를 처리하고 있다(NonBlocking). 하지만 업무 특성상 A업무가 완료되어야 B 업무가 수행될 수 있는 순차적인 경향을 보이고 있다(Sync). 2번 케이스 역시 팀장님은 업무를 지시하고 다른 업무를 처리하고 있다(NonBlocking). 업무 특성상 동시에 진행되어도 무방한 상황이다. 그래서인지 업무가 완료되는 시기도 모두 다르다. 정리하자면 1번 케이스에서 팀장님은 업무를 지시함과 동시에 다른 업무를 진행하고 있다. 하지만 전체 프로젝트 플로우에서 A업무가 완료되어야 B업무를 수행할 수 있는 등 프로젝트가 순차적으로 진행되어야 한다. 2번 케이스 역시 팀장님은 업무를 지시함과 동시에 다른 업무를 진행하고 있다. 하지만 프로젝트 내부 업무 간의 영향이 없는 탓에, 모든 사원들이 각자 맡은 업무를 동시에 진행하고 있다. 마무리 사실 Blocking과 NonBlocking. Sync와 Async의 개념은 지독하게 추상적이라고 생각한다. 어느 레벨에서 바라보느냐의 관점 차이도 있겠고, 여러 포스팅을 찾아보면서 느낀 점이지만 전부 예시를 들어서 설명하고 있고 설명하는 방식이 모두 다르다. 특히 Sync와 Async에서. 그래서 더 헷갈렸던 것 같다. 해당 조합들을 대용량 트래픽 환경에서의 File I/O, Network I/O 등 꼭 필요한 케이스에서는 성능과 부하 분산에 효율적이기 때문에, 꼭 필요하다고 생각한다. 하지만 그렇지 상황에 맞지 않은 경우를 사용하였다가 오히려 역효과를 낼 수도 있다고 생각한다.(실제로 FastAPI 공식문서에서도, 잘 모르겠으면 그냥 def를 쓰라고 권하고있다.) ⭐어떤 조합이든 상황에 맞게 사용하는게 제일 효율적일 것 같다 !⭐ 다음 시간에는 파이썬에서의 Sync, Async 처리 FastAPI에서 비동기 처리가 가능한 이유 Sync / Async, FastAPI에서의 코드 예제 (feat. 비동기가 아닐때에, def를 권장하는 이유) 까지 다뤄볼 예정이다. 출처 https://fastapi.tiangolo.com/async/ https://www.youtube.com/watch?v=XNGfl3sfErc https://velog.io/@msgooday/동기-비동기 https://inpa.tistory.com/entry/👩‍💻-동기비동기-블로킹논블로킹-개념-정리 https://velog.io/@nittre/블로킹-Vs.-논블로킹-동기-Vs.-비동기 https://keyhyuk-kim.medium.com/fastapi-는-non-async-함수-비동기로-처리하기-8e3345a69517 https://www.youtube.com/watch?v=IdpkfygWIMk https://www.youtube.com/watch?v=oEIoqGd-Sns https://incheol-jung.gitbook.io/docs/q-and-a/java/or-or-or https://jh-7.tistory.com/25
김원준
👍❤️😀😘
9
Clean Code 깊게파보기
개요 개발을 하면서 과거에 작업했던 코드를 다시 봐야 하는 상황이 종종 있다. 과거에 깨끗하지 않게 코드를 작성했다면, 코드를 다시 이해하고 원인을 찾는 부분에서 시간을 소요 할 가능성이 높다. 특히, 서비스 중인 프로그램에서 버그가 발생해 빠르게 이슈 대응을 해야 한다면, 머리가 새하얘질 것 이다. 또한, 이런 경험을 한 적이 있을 것이다. 시간이 부족해서 빠르게 개발하고, ‘아.. 나중에 리팩토링 해야겠다.’ 라고 생각한 경우도 있을 것이다. 하지만, 리팩토링을 하는 Task를 따로 추가하는 경우는 매우 희박한 경험들이 있을 것이다. 이런 경험을 하면서 개발 초기 부터 이해가 잘되는 코드를 만들기 위한 방법을 찾아 보게 되었고, 클린 코드에 대해 알게 되면서 학습을 진행했다. 클린 코드를 알기 전 개발에 급급해서 만들었던 과거의 코드 클린 코드란? 한 개발자는 클린 코드에 대해 다음과 같이 말했다. 그래디 부치(Grady Booch) ”클린 코드는 단순하고 직접적이다. 클린 코드는 잘 쓴 문장처럼 읽힌다. 클린 코드는 설계자의 의도를 숨기지 않는다. 오히려 명쾌한 추상화와 단순한 제어문으로 가득하다." 이 외에도 여러 개발자들의 말을 정리하면 다음과 같다. 다른 사람이 읽기 쉬운 코드 유지 보수가 쉬운 코드 간단 명료하고, 의도가 분명한 코드 클린 코드에 대해 많은 말들이 있지만 개인적으로 클린코드의 핵심은 라고 생각 된다. “누구에게나” 라고 생각한 이유는 프로젝트는 팀원들과 같이 진행을 하기 때문에 내가 작성한 코드를 팀원들이 읽기 때문이다. 클린 코드를 실천하면 개인의 생산성을 높이는 것 외에도 팀의 생산성을 높이는데 기여를 한다고 생각된다. 클린 코드가 무엇 인지 알았으면 이제는 클린코드를 실천하는 방법에 대해 알아볼 차례이다. 이 번 글에서는 Python 에서 클린 코드를 적용하는 방법에 대해 알아볼 것이다. 이해하기 쉬운 이름 (변수 명) 코드 악취(Code Smell) 감지와 대응 이해하기 쉬운 이름 PEP 8의 명명 규약 PEP 8 문서에는 파이썬 명명 규약과 관련된 권장 사항이 몇 가지가 존재한다. 모든 문자는 아스키 문자여야 한다. 강세 표시 부호가 없는 영문 대소문자로 표기해야 한다. 모듈 이름은 짧아야 하며 모두 소문자로 표기한다. 클래스 이름은 파스칼(SomeClassName) 표기법으로 작성한다. 상수 변수는 대문자 스네이크(SOME_API_KEY) 표기법으로 작성한다. 함수, 메소드, 변수 이름은 소문자 스네이크(find_user_id()) 표기법으로 적어야 한다. 메소드에 대한 첫 번째는 인수는 항상 소문자로 self라고 이름을 붙여야 한다. 클래스 메소드에 대한 첫 번째 인수는 항상 소문자로 cls 라고 이름을 붙여야 한다. 클래스의 프라이빗 속성은 항상 _ 로 시작해야 한다. 클래스의 퍼블릭 속성은 절대로 _ 로 시작해서는 안된다. PEP 8에는 프로그래머가 해당 지침을 엄격하게 따를 필요는 없다고 한다. 예를 들어 변수명에 스네이크 표기법이 아닌 카멜 케이스(camelCase)를 사용해도 된다는 얘기다. 하지만 중요한 점은 가독성을 위해 표기법에 대한 일관성이 필요하다. 이름의 적정 길이 변수명은 “적당한” 길이로 만들어야 한다. 너무 길다면 입력하기 귀찮고, 너무 짧다면 변수의 의미를 혼동할 수가 있다. 하지만, 코드를 쓰는 것 보다 보통은 읽는 경우가 많기 때문에 피할 수 없다면 긴 이름을 선택하여 의미 혼동을 적게 하는 것이 더 바람직하다. 너무 짧은 이름 변수명을 너무 짧게 작성한다면 처음에는 적절한 단어로 보일 수 있지만, 나중에 코드를 확인하면 처음에 생각했던 의미를 잊어 버릴 수가 있다. 개발자가 자주 사용하는 짧은 변수 명(예시) 한두 글자로 된 이름 number의 축약으로 n을 적고 싶은 경우가 있을 것이다. 하지만 n으로 시작하는 단어가 많아 다른 개발자가 봤을 때, 의미를 바로 파악하지 못하는 경우가 발생할 수 있다. 또한 IDE에서 변수 명 찾기를 했을 때, n이 포함된 단어들이 나와 찾고 싶은 변수의 위치를 찾는데 방해가 될 확률이 높다. 줄임말 month, monitor, monster의 의미로 mon으로 축약하는 경우가 있다. 여러 단어를 의미 할 수가 있어 이런 표기는 피하는 것 이 좋다. 과거에는 단어들을 축약해서 변수명을 만드는 스타일이 유행했다. memcpy, strcmp 등 하지만 읽기 힘든 스타일이기 때문에 오늘날에는 사용하지 않는 것이 좋다. start와 같은 한 단어 이름도 모호할 수 있다. “무엇의 시작인가?” 이렇게 통상적으로 사용되는 단어의 경우 코드의 맥락을 확인 하기 위해 한번 더 생각해야 하는 문제가 (시간 소요) 발생할 수 있다. 하지만, 한 글자로 변수명을 사용해도 되는 예외적인 상황도 있다. 너무 긴 이름 일반적으로, 이름은 쓰이는 범위가 넓을 수록 더 설명적인 이름을 사용 해야 한다. 짧은 함수나 코드에서 start를 사용한다면 의미가 모호해지는 경우가 아니라면 사용을 해도 괜찮다. 하지만 전역변수로 start를 사용한다면 추가적인 설명이 포함된 변수명으로 만들어야 할 것이다. 긴 변수 명에 대한 지침 이름에 붙이는 접두사 오래된 코딩 방식 중 하나인 헝가리식 표기법이 있다. 헝가리식 표기법은 변수 앞에 접두사로 데이터 타입을 적는 방식이다. list_indexes 와 같이 index들이 List 데이터 타입으로 들어있다는 것을 의미한다. 요즘의 IDE의 경우 데이터 타입이 무엇인지 나오기 때문에 접두사 없이도 파악할 수 있다. 이름의 순차적 숫자 접미사 변수명이 payment1, payment2 … 등의 숫자가 붙어 있다면 변경해야한다. 이런 변수들이 있다면, 튜플이나 리스트로 담아서 사용하는 것을 권장한다. 함수 명이 find_payment1(), find_payment2() 등으로 되어있다면 find_payment(1), find_payment(2) 등으로 인수로 받는 함수로 만들거나 payment의 의미를 조금더 세분화 하여 만들어야한다. find_1st_quarter_payment(), find_2nd_quarter_pament() 등 순차적 접미사가 있는 이름을 선택한 이유가 타당하다면 사용해도 좋다. 하지만, 그냥 만들기 쉽다는 의미로 만들었다면 수정할 필요가 있다. 검색 가능한 이름 짓기 앞서 말했듯이 IDE에서의 검색기능을 활용하기 위해서는 긴 변수명을 사용하여 고유한 이름을 만들 필요가 있다. 또한, 최근의 IDE의 경우 전역변수, 지역변수 등을 구분하여 rename을 편리하게 할 수 있는 기능들이 존재한다. 하지만 항상 이런 IDE들을 사용하는 경우는 없기 때문에 최악의 상황을 생각해서 고유의 변수명을 만들어 주도록 해야한다. 농담, 말장난, 문화적 참조는 피하자 프로그램에서 이름을 선택할 때 농담이나 말장난 등을 사용하여 코드의 경쾌함을 넣고 싶어하는 개발자가 있다. 하지만, 이런 방식으로 이름을 넣는 다면, 후임 개발자나 농담을 모르는 개발자는 오타로 착각하여 버그 신고를 할 가능성이 존재한다. 항상 이름을 만들 때는 영어권 사용자가 아닌 사람들도 쉽게 이해를 할 수 있도록 직설적이고, 유머가 없는 이름으로 작성해야 한다. 코드 악취 감지와 대응 냄새로 가스 누출을 알아채거나 화재를 감지할 수 있는 것처럼 코드 악취(Code Smell)는 잠재적인 버그를 암시하는 소스 코드 패턴 입니다. 코드 악취가 있다고 해서 반드시 문제가 생기는 것은 아니지만, 적어도 프로그램을 조사할 필요가 있습니다. 코드 악취가 될 수 있는 항목은 다음과 같습니다. 중복된 코드 매직 넘버 주석 처리된 코드와 죽은 코드 숫자 접미사가 붙은 변수 그냥 함수나 모듈이어야 하는 클래스 중첩된 리스트 컴프리헨션 빈 예외처리 블록과 부실한 에러 메세지 중복된 코드 가장 흔한 코드 악취는 중복된 코드 모든 코드 악취가 그렇듯이, 꼭 제거를 할 필요는 없다. 하지만 중복되는 코드가 3군데 이상으로 많아지게 된다면 코드를 함수화를 하거나 반복문을 사용하는 것을 고려 해야 한다. 이를 무시하게 된다면, 오타로 인한 버그로 인해 추가적인 시간이 소요되거나 혹은 유지 보수를 해야하는 상황에서 추가적인 시간을 사용하게 될 것이다. 매직 넘버 프로그래밍을 하면서 숫자를 사용하는 일은 아주 많다. 이를 프로그래밍을 할 때 매직넘버(의미 있는 이름의 상수로 대체될 수 있는 숫자)라는 표현을 쓴다. 매직넘버 또한 코드 악취이다. 개발자의 의도를 제대로 전달하지 못하기에 코드의 가독성은 떨어지고, 업데이트 하기도 힘들어지며 감지하기 어려운 점이 있다. 이를 해결하기 위해 상수를 사용하여 코드 악취를 제거 할 수 있다. 코드로 예를 들어 설명하면 아래와 같은 경우이다. 코드안에 인라인 주석을 통해 1주일이라는 정보를 알려줄 수도 있지만, 더 좋은 방법은 상수들로 풀어서 사용하는 것이다. 상수는 숫자가 아닌 값에 적용해도 좋다. Python Enum Class Python은 열거형 enum을 지원합니다. 열거형(enumeration)은 고유한 상수값에 연결된 기호 이름의 집합입니다. 열거형은 상수를 나타내는 데 보통 사용되기 때문에 열거형 멤버에 대핸 대문자로 사용하는 것을 지향합니다. 주석 처리된 코드와 죽은 코드 개발을 하면서 일시적으로 코드 일부를 주석 처리하는 것은 흔한 과정인 만큼 자주 사용한다. 죽은 코드는 간단하게 말해 논리적으로 절대 실행될 수 없는 코드이거나, 도달 할 수 없는 코드이다. 주석 처리가 된 코드와 죽은 코드가 그대로 남아 있게 된다면, 이를 처음 본 다른 개발자는 왜 코드에서 제거되었고, 향후에 어떤 부분에 필요한지 모르는 상태가 된다. 중요하지 않은 내용 이여도 이것을 파악하는데 있어 다른 개발자는 추가적인 시간을 소요 하게 될 것이다. 그냥 함수나 모듈이어야 하는 클래스 자바를 먼저 사용했던 개발자들은 클래스를 만드는 것에 익숙하다. 하지만 이런 습관이 파이썬에 적용된다면 코드 악취를 발생 시킬 수 있다. 파이썬은 클래스나 보일러 플레이트에 코드가 존재할 필요가 없기 때문에 다른 언어에 비해 코드를 구성하는 부분에서 조금 더 자유롭다. 즉, 일회성 함수를 위해 객체를 만들거나 정적 메소드만 포함된 클래스를 작성하는 것 보다 함수를 만들고, 이들을 묶어 모듈화를 하는 것이 조금 더 효율적인 프로그래밍이 될 수 있다. 중첩된 리스트 컴프리헨션 파이썬은 리스트 컴프리헨션 이라는 것을 제공한다. 반복문을 한번만 사용하는 경우 리스트 컴프리헨션이 깔끔한 코드가 될 수 있다. 하지만, for문이 중첩이 되는 경우 이를 리스트 컴프리헨션으로 만든 다면 코드악취의 원인이 될 수있다. 빈 예외 처리 블록과 부실한 에러 메세지 파이썬의 try-except 구문은 프로그램에 문제가 발생하여도 계속 작동이 되도록 하는 구문이다. 프로그래머들은 except 처리를 어떻게 진행 할지 결정하기 어려울 수가 있어 except 블록을 pass 처리하고 싶은 유혹에 빠지기 쉽다. 이러한 코드들은 에러 발생으로 인한 코드 충돌은 발생하지 않는다. 하지만, 그냥 넘어가는 것은 충돌보다 더 안좋은 상황을 만들 수도 있다. 프로그램에서 발생할 수 있는 모든 예외를 처리하지 않으면 프로그램 개발은 완료된 것이 아님을 명시해야 한다. 마무리 클린 코드에 대한 내용은 위에 정리한 내용(코드 적인 부분이나 Docstring 등)외에도 많은 내용(클린 아키텍처 등)을 포함하고 있다. 아직 공부해야 하는 부분들은 많지만 클린 코드의 핵심인 “누구에게나 쉽게 읽히는 코드”를 만들기 위해 노력할 것이다. 출처: 클린 코드, 이제는 파이썬이다: “알 스웨이가트”
Lighthouse
👍❤️😘
4
하둡 - 아파치 프로젝트 및 KHP
아파치 프로젝트 아파치 프로젝트는 오픈 소스 소프트웨어 개발을 위한 비영리 조직입니다. 하둡은 아파치 프로젝트의 핵심 프로젝트 중 하나입니다. 아파치 프로젝트는 하둡의 개발, 유지 관리, 보급을 담당하고 있습니다. 아파치 프로젝트는 하둡의 안정성과 성능을 향상시키기 위해 지속적으로 노력하고 있습니다. 또한, 하둡의 사용을 지원하기 위한 다양한 도구와 리소스를 제공하고 있습니다. KHP(카카오하둡) KHP는 카카오가 자체 개발한 하둡 배포판입니다. KHP는 하둡의 최신 버전을 기반으로 개발되었으며, 카카오의 요구 사항에 맞게 최적화되어 있습니다. KHP는 다음과 같은 특징을 가지고 있습니다. 높은 확장성: KHP는 대규모 클러스터 환경에서의 안정적인 운영을 지원합니다. 높은 성능: KHP는 하둡의 성능을 향상시키기 위한 다양한 최적화 기술을 적용하고 있습니다. 쉽고 편리한 관리: KHP는 하둡의 관리를 단순화하기 위한 다양한 기능을 제공합니다. KHP는 카카오의 빅데이터 플랫폼의 기반으로 사용되고 있습니다. 또한, 카카오 외에도 다양한 기업과 기관에서 KHP를 사용하고 있습니다.
Lighthouse
😘😀👍❤️
4
하둡 - Map Reduce
MapReduce는 대규모 데이터를 분산 환경에서 처리하기 위한 프로그래밍 모델입니다. MapReduce는 입력 데이터를 키-값 쌍으로 변환하는 Map 단계와, 동일한 키를 가진 데이터를 집계하는 Reduce 단계로 구성됩니다. MapReduce는 다음과 같은 특징을 가지고 있습니다. 병렬 처리: MapReduce는 입력 데이터를 여러 노드에 분산하여 처리합니다. 이를 통해 대규모 데이터를 효율적으로 처리할 수 있습니다. 간결한 프로그래밍: MapReduce는 단순한 프로그래밍 모델을 제공합니다. 이를 통해 개발자가 대규모 데이터를 쉽게 처리할 수 있습니다. 확장성: MapReduce는 확장성이 뛰어납니다. 이를 통해 대규모 데이터 처리 환경에 쉽게 적용할 수 있습니다. MapReduce의 구조 MapReduce는 다음과 같은 구조로 구성됩니다. JobTracker: JobTracker는 MapReduce 작업을 관리하는 서버입니다. JobTracker는 MapReduce 작업을 분배하고, 작업의 진행 상황을 추적합니다. TaskTracker: TaskTracker는 MapReduce 작업을 수행하는 서버입니다. TaskTracker는 JobTracker의 명령에 따라 MapReduce 작업을 수행합니다. MapReduce의 작동 방식 MapReduce는 다음과 같은 방식으로 작동합니다. 사용자는 MapReduce 작업을 생성합니다. JobTracker는 MapReduce 작업을 분배합니다. TaskTracker는 MapReduce 작업을 수행합니다. JobTracker는 작업의 진행 상황을 추적합니다. 사용자는 JobTracker를 통해 MapReduce 작업을 생성할 수 있습니다. JobTracker는 MapReduce 작업을 여러 TaskTracker에 분배합니다. TaskTracker는 JobTracker의 명령에 따라 MapReduce 작업을 수행합니다. JobTracker는 작업의 진행 상황을 추적합니다. MapReduce의 단계 MapReduce는 다음과 같은 두 단계로 구성됩니다. Map 단계: Map 단계는 입력 데이터를 키-값 쌍으로 변환합니다. Map 단계는 입력 데이터를 한 줄씩 읽어 키-값 쌍으로 변환합니다. Reduce 단계: Reduce 단계는 동일한 키를 가진 데이터를 집계합니다. Reduce 단계는 Map 단계의 출력을 키-값 쌍으로 받고, 동일한 키를 가진 데이터를 집계합니다. MapReduce는 다양한 분야에서 활용되고 있습니다. 예를 들어, 빅데이터 분석, 디지털 아카이빙, 미디어 스트리밍 등에서 MapReduce가 사용되고 있습니다. MapReduce의 장점 MapReduce는 다음과 같은 장점을 가지고 있습니다. 병렬 처리: MapReduce는 입력 데이터를 여러 노드에 분산하여 처리합니다. 이를 통해 대규모 데이터를 효율적으로 처리할 수 있습니다. 간결한 프로그래밍: MapReduce는 단순한 프로그래밍 모델을 제공합니다. 이를 통해 개발자가 대규모 데이터를 쉽게 처리할 수 있습니다. 확장성: MapReduce는 확장성이 뛰어납니다. 이를 통해 대규모 데이터 처리 환경에 쉽게 적용할 수 있습니다. MapReduce의 단점 MapReduce는 다음과 같은 단점을 가지고 있습니다. 복잡성: MapReduce는 복잡한 구조를 가지고 있습니다. 따라서 MapReduce를 사용하려면 충분한 이해가 필요합니다. 성능: MapReduce의 성능은 네트워크 대역폭에 따라 제한될 수 있습니다. MapReduce의 활용 사례 MapReduce는 다음과 같은 분야에서 활용되고 있습니다. 빅데이터 분석: MapReduce는 대규모 데이터를 분석하기 위한 플랫폼으로 사용될 수 있습니다. 예를 들어, 로그 데이터를 분석하여 고객 행동을 분석하거나, 금융 데이터를 분석하여 이상 거래를 감지하는 데 MapReduce를 사용할 수 있습니다. 디지털 아카이빙: MapReduce는 디지털 아카이빙을 위한 플랫폼으로 사용될 수 있습니다. 예를 들어, 정부 기관은 공공 데이터를 MapReduce에 저장하여 보관할 수 있습니다. 미디어 스트리밍: MapReduce는 미디어 스트리밍을 위한 플랫폼으로 사용될 수 있습니다. 예를 들어, 온라인 동영상 스트리밍 서비스는 MapReduce를 사용하여 동영상을 저장하고 스트리밍할 수 있습니다.
Lighthouse
😀😘
2
하둡 - HDFS
HDFS(Hadoop Distributed File System)는 하둡 에코시스템의 핵심 구성 요소 중 하나로, 대용량 데이터를 저장하고 관리하기 위한 분산 파일 시스템입니다. HDFS는 수백 대 또는 수천 개의 서버에 분산된 데이터를 저장하여 대규모 데이터 처리를 가능하게 합니다. HDFS는 다음과 같은 특징을 가지고 있습니다. 분산: HDFS는 데이터를 여러 서버에 분산하여 저장합니다. 이를 통해 대규모 데이터를 저장하고 관리할 수 있습니다. 내결함성: HDFS는 데이터의 손실을 방지하기 위해 내결함성을 갖추고 있습니다. 데이터는 여러 서버에 복제되어 저장되며, 서버 하나가 고장나더라도 데이터를 복구할 수 있습니다. 효율성: HDFS는 데이터를 효율적으로 저장하고 관리합니다. 데이터는 블록 단위로 저장되며, 블록의 크기는 64MB에서 128MB 사이로 조정할 수 있습니다. HDFS는 다음과 같은 용도로 사용될 수 있습니다. 대규모 데이터 저장: HDFS는 수백 TB 또는 수 PB 이상의 데이터를 저장할 수 있습니다. 대규모 데이터 분석: HDFS는 대규모 데이터를 분석하기 위한 플랫폼으로 사용될 수 있습니다. 디지털 아카이빙: HDFS는 디지털 아카이빙을 위한 플랫폼으로 사용될 수 있습니다. HDFS의 구조 HDFS는 다음과 같은 구조로 구성되어 있습니다. NameNode: NameNode는 HDFS의 메타데이터를 저장하는 서버입니다. 메타데이터에는 파일의 이름, 크기, 위치 등이 포함됩니다. DataNode: DataNode는 실제 데이터를 저장하는 서버입니다. DataNode는 NameNode의 명령에 따라 데이터를 저장하고 관리합니다. HDFS의 작동 방식 HDFS는 다음과 같은 방식으로 작동합니다. 사용자가 파일을 생성하면 NameNode는 파일의 메타데이터를 저장합니다. NameNode는 DataNode에 파일을 저장할 위치를 지시합니다. DataNode는 NameNode의 지시에 따라 파일을 저장합니다. 사용자는 NameNode를 통해 파일을 생성, 수정, 삭제할 수 있습니다. NameNode는 DataNode에 파일을 저장할 위치를 지시하며, DataNode는 NameNode의 지시에 따라 파일을 저장하고 관리합니다. HDFS의 장점 HDFS는 다음과 같은 장점을 가지고 있습니다. 대규모 데이터 저장: HDFS는 수백 TB 또는 수 PB 이상의 데이터를 저장할 수 있습니다. 내결함성: HDFS는 데이터의 손실을 방지하기 위해 내결함성을 갖추고 있습니다. 효율성: HDFS는 데이터를 효율적으로 저장하고 관리합니다. HDFS의 단점 HDFS는 다음과 같은 단점을 가지고 있습니다. 복잡성: HDFS는 복잡한 구조를 가지고 있습니다. 따라서 HDFS를 사용하려면 충분한 이해가 필요합니다. 성능: HDFS의 성능은 네트워크 대역폭에 따라 제한될 수 있습니다. HDFS의 활용 사례 HDFS는 다음과 같은 분야에서 활용되고 있습니다. 빅데이터 분석: HDFS는 대규모 데이터를 분석하기 위한 플랫폼으로 사용될 수 있습니다. 예를 들어, 로그 데이터를 분석하여 고객 행동을 분석하거나, 금융 데이터를 분석하여 이상 거래를 감지하는 데 HDFS를 사용할 수 있습니다. 디지털 아카이빙: HDFS는 디지털 아카이빙을 위한 플랫폼으로 사용될 수 있습니다. 예를 들어, 정부 기관은 공공 데이터를 HDFS에 저장하여 보관할 수 있습니다. 미디어 스트리밍: HDFS는 미디어 스트리밍을 위한 플랫폼으로 사용될 수 있습니다. 예를 들어, 온라인 동영상 스트리밍 서비스는 HDFS를 사용하여 동영상을 저장하고 스트리밍할 수 있습니다. HDFS는 대규모 데이터를 저장하고 관리하기 위한 강력한 도구입니다. HDFS를 사용하면 대규모 데이터를 효율적으로 저장하고 관리할 수 있습니다.
Lighthouse
😘😀👍
3
하둡 에코시스템 - 개요
오늘은 대용량 데이터 처리를 위한 프레임워크인 Hadoop에 대해 간단히 소개해드리려고 합니다. Hadoop이란? Hadoop은 Apache Software Foundation에서 개발한 오픈소스 프레임워크로, 대용량 데이터 처리를 위한 분산 처리 시스템입니다. Hadoop은 MapReduce와 HDFS라는 두 가지 주요 기술을 기반으로 합니다. MapReduce는 대용량 데이터를 처리하기 위한 분산 처리 프레임워크입니다. MapReduce는 데이터를 작은 단위로 나누어 병렬 처리하는 방식으로 대용량 데이터를 효율적으로 처리할 수 있습니다. HDFS는 대용량 데이터를 저장하기 위한 분산 파일 시스템입니다. HDFS는 데이터를 여러 대의 서버에 분산 저장하여 대용량 데이터를 효율적으로 저장하고 관리할 수 있습니다. Hadoop의 특징 Hadoop의 주요 특징은 다음과 같습니다. 분산 처리: Hadoop은 대용량 데이터를 처리하기 위해 분산 처리 방식을 사용합니다. 확장성: Hadoop은 클러스터 규모를 쉽게 확장할 수 있습니다. 내구성: Hadoop은 데이터의 손실을 방지하기 위해 다양한 내구성 기능을 제공합니다. 오픈소스: Hadoop은 오픈소스 소프트웨어로, 누구나 무료로 사용할 수 있습니다. Hadoop의 적용 Hadoop은 다양한 분야에서 대용량 데이터 처리를 위해 사용되고 있습니다. Hadoop의 주요 적용 분야는 다음과 같습니다. 웹로그 분석: Hadoop은 웹로그 분석을 위한 가장 인기 있는 도구 중 하나입니다. 빅데이터 분석: Hadoop은 빅데이터 분석을 위한 강력한 도구입니다. 실시간 처리: Hadoop은 실시간 처리를 위한 다양한 기능을 제공합니다. Hadoop을 학습하기 위한 참고 자료는 다음과 같습니다. 책 Hadoop: The Definitive Guide by Tom White Hadoop in Action by Josh Long and Hortonworks 강좌 Hadoop tutorial by Cloudera Hadoop training by Hortonworks Hadoop은 대용량 데이터 처리를 위한 강력한 프레임워크입니다. Hadoop을 잘 이해하고 사용하면 대용량 데이터를 효율적으로 처리할 수 있습니다.
Lighthouse
👍😘😀
4
디자인 패턴 - Observer
오늘은 디자인 패턴 중 하나인 Observer 패턴에 대해 간단히 소개해드리려고 합니다. Observer 패턴이란? Observer 패턴은 객체의 상태 변화를 관찰하는 객체들을 등록하고, 객체의 상태가 변경될 때마다 등록된 객체들에게 알림을 보내는 패턴입니다. 즉, 객체의 상태 변화를 관찰하고 싶은 객체들을 객체에 등록하고, 객체의 상태가 변경될 때마다 등록된 객체들에게 알림을 보내는 방식으로 객체의 상태 변화를 관리합니다. Observer 패턴의 장점 Observer 패턴을 사용하면 다음과 같은 장점이 있습니다. 객체의 상태 변화를 관찰하고 싶은 객체들을 쉽게 관리할 수 있습니다. 객체의 상태 변화를 관찰하는 객체들을 쉽게 추가하거나 제거할 수 있습니다. 객체의 상태 변화를 관찰하는 객체들 간의 결합도를 낮출 수 있습니다. Observer 패턴의 예시 Observer 패턴의 예시로 게임의 캐릭터를 생각해 볼 수 있습니다. 게임의 캐릭터는 자신의 상태가 변경될 때마다, 이를 관찰하고 있는 다른 캐릭터들에게 알림을 보냅니다. 다음은 Observer 패턴을 사용하여 게임의 캐릭터를 구현한 예시입니다. Python Code 위 코드에서 Character 클래스는 observers라는 리스트를 사용하여 Observer 객체들을 관리합니다. notifyObservers() 메서드는 observers 리스트에 등록된 모든 Observer 객체들에게 알림을 보냅니다. Enemy 클래스는 Character 클래스를 상속받아 구현됩니다. Enemy 클래스는 hp 필드를 사용하여 적의 체력을 관리합니다. changeState() 메서드는 적의 체력이 0 이하가 되면, notifyObservers() 메서드를 호출하여 플레이어에게 알림을 보냅니다. Player 클래스도 Character 클래스를 상속받아 구현됩니다. Player 클래스는 attack_power 필드를 사용하여 플레이어의 공격력을 관리합니다. update() 메서드는 notifyObservers() 메서드를 호출하여 적에게 알림을 보냅니다. 클라이언트 코드에서는 enemy 객체와 player 객체를 생성합니다. 그리고 enemy 객체에 player 객체를 Observer 객체로 등록합니다. enemy 객체의 changeState() 메서드를 호출하면, player 객체에게 알림이 전달됩니다. player 객체는 알림을 수신하여 적의 체력이 0 이하가 되었다는 것을 확인합니다. Observer 패턴의 적용 Observer 패턴은 다음과 같은 상황에서 유용하게 사용할 수 있습니다. 객체의 상태 변화를 관찰하고 싶은 객체들이 있는 경우 객체의 상태 변화를 관찰하는 객체들을 쉽게 추가하거나 제거할 수 있어야 하는 경우 객체 Sources: github.com/HongdaChen/GitChat github.com/icexmoon/design-pattern-with-python subject to license (MIT)
Lighthouse
😘😀👏👍
4
디자인 패턴 - Singelton
오늘은 디자인 패턴 중 하나인 Singleton 패턴에 대해 간단히 소개해드리려고 합니다. Singleton 패턴이란? Singleton 패턴은 클래스에 단 하나의 인스턴스만 생성되도록 하는 패턴입니다. 즉, 클래스의 인스턴스를 생성하는 방법을 제한하여 클래스에 단 하나의 인스턴스만 생성되도록 합니다. Singleton 패턴의 장점 Singleton 패턴을 사용하면 다음과 같은 장점이 있습니다. 클래스에 단 하나의 인스턴스만 생성되도록 보장할 수 있습니다. 클래스의 인스턴스를 공유할 수 있습니다. 클래스의 인스턴스를 캡슐화할 수 있습니다. Singleton 패턴의 예시 Singleton 패턴의 예시로 게임의 주인공을 생각해 볼 수 있습니다. 게임의 주인공은 항상 하나만 존재해야 합니다. 따라서 게임의 주인공을 Singleton 패턴으로 구현할 수 있습니다. 다음은 Singleton 패턴을 사용하여 게임의 주인공을 구현한 예시입니다. Python Code 위 코드에서 Hero 클래스는 __instance라는 클래스 변수를 사용하여 Singleton 패턴을 구현합니다. __instance 변수는 Hero 클래스의 인스턴스를 참조합니다. Hero 클래스의 getInstance() 메서드는 __instance 변수가 None이면 새로운 Hero 인스턴스를 생성하고, None이 아니면 __instance 변수에 저장된 인스턴스를 반환합니다. 클라이언트 코드에서는 Hero 클래스의 getInstance() 메서드를 사용하여 Hero 클래스의 인스턴스를 얻을 수 있습니다. getInstance() 메서드는 항상 동일한 Hero 인스턴스를 반환합니다. Singleton 패턴의 적용 Singleton 패턴은 다음과 같은 상황에서 유용하게 사용할 수 있습니다. 클래스에 단 하나의 인스턴스만 생성되도록 보장해야 하는 경우 클래스의 인스턴스를 공유해야 하는 경우 클래스의 인스턴스를 캡슐화해야 하는 경우 Singleton 패턴은 디자인 패턴 중에서도 가장 기본적인 패턴 중 하나입니다. 따라서 디자인 패턴을 학습하는 개발자라면 Singleton 패턴을 반드시 이해하고 있어야 합니다. Singleton 패턴을 사용할 때는 다음과 같은 주의 사항을 고려해야 합니다. Singleton 패턴을 사용하면 클래스에 단 하나의 인스턴스만 생성되므로, 클래스의 인스턴스를 여러 번 생성해야 하는 경우에는 Singleton 패턴을 사용하지 않는 것이 좋습니다. Singleton 패턴을 사용하면 클래스의 인스턴스를 공유하므로, 인스턴스의 상태가 변경될 때는 동시성 문제가 발생할 수 있습니다. 따라서 인스턴스의 상태를 변경할 때는 동시성 문제를 고려해야 합니다. Singleton 패턴을 사용할 때는 이러한 주의 사항을 고려하여 사용해야 합니다. 오늘 소개해드린 내용을 바탕으로 Singleton 패턴에 대한 이해를 넓혀나가시기 바랍니다. 감사합니다.
Lighthouse
❤️😘😀👍
5
디자인 패턴 - Factory Method
안녕하세요, 개발자 여러분! 오늘은 디자인 패턴 중 하나인 Factory Method 패턴에 대해 간단히 소개해드리려고 합니다. Factory Method 패턴이란? Factory Method 패턴은 객체를 생성하는 책임을 서브클래스에게 위임하는 패턴입니다. 즉, 객체의 생성 방법을 클라이언트 코드에서 결정하지 않고, 서브클래스에서 결정하도록 합니다. Factory Method 패턴의 장점 Factory Method 패턴을 사용하면 다음과 같은 장점이 있습니다. 객체의 생성 방법을 클라이언트 코드에서 분리할 수 있습니다. 객체의 생성 방법을 확장하기 쉽습니다. 객체의 생성 방법을 캡슐화할 수 있습니다. Factory Method 패턴의 예시 Factory Method 패턴의 예시로 자동차 공장을 생각해 볼 수 있습니다. 자동차 공장은 자동차를 생산하는 역할을 합니다. 하지만 자동차의 종류는 다양합니다. 따라서 자동차 공장은 자동차의 종류에 따라 다른 자동차를 생성해야 합니다. 이 경우 Factory Method 패턴을 사용하여 자동차의 종류에 따라 다른 자동차를 생성할 수 있습니다. 다음은 Factory Method 패턴을 사용하여 자동차 공장을 구현한 예시입니다. Python Code 위 코드에서 CarFactory 클래스는 create_car() 메서드를 통해 자동차를 생성합니다. create_car() 메서드는 자동차의 종류를 인수로 받습니다. 그리고 인수로 받은 자동차의 종류에 따라 Sedan 클래스 또는 SportsCar 클래스의 인스턴스를 생성합니다. 클라이언트 코드에서는 CarFactory 클래스의 create_car() 메서드를 사용하여 자동차를 생성합니다. create_car() 메서드에 자동차의 종류를 인수로 전달하면, CarFactory 클래스는 해당 종류의 자동차를 생성하여 반환합니다. Factory Method 패턴의 적용 Factory Method 패턴은 다음과 같은 상황에서 유용하게 사용할 수 있습니다. 객체의 생성 방법을 확장하기 쉬운 경우 객체의 생성 방법을 캡슐화해야 하는 경우 다양한 종류의 객체를 생성해야 하는 경우 Factory Method 패턴은 디자인 패턴 중에서도 가장 많이 사용되는 패턴 중 하나입니다. 따라서 디자인 패턴을 학습하는 개발자라면 Factory Method 패턴을 반드시 이해하고 있어야 합니다. 오늘 소개해드린 내용을 바탕으로 Factory Method 패턴에 대한 이해를 넓혀나가시기 바랍니다.
Lighthouse
😘😀❤️
3
디자인 패턴 - 알아보기
오늘은 개발자라면 꼭 알아야 할 디자인 패턴에 대해 간단히 소개해드리려고 합니다. 디자인 패턴이란? 디자인 패턴은 소프트웨어 설계에서 자주 발생하는 문제를 해결하기 위한 일반적인 해결책입니다. 이 패턴들은 미리 만들어진 청사진과도 같은데, 커스터마이징하여 코드에서 반복되는 설계 문제를 해결할 수 있습니다. 디자인 패턴의 장점 디자인 패턴을 사용하면 다음과 같은 장점이 있습니다. 코드의 재사용성 및 유지보수성을 높일 수 있습니다. 설계의 일관성을 유지할 수 있습니다. 프로젝트의 규모가 커질수록 발생할 수 있는 문제들을 예방할 수 있습니다. 디자인 패턴의 종류 디자인 패턴은 크게 생성 패턴, 구조 패턴, 행위 패턴으로 나눌 수 있습니다. 생성 패턴은 새로운 객체를 생성하는 방법에 대한 패턴입니다. 디자인 패턴 공부 방법 디자인 패턴을 학습하는 방법은 크게 두 가지가 있습니다. 책이나 강의를 통해 이론적으로 학습하는 방법 실제 프로젝트에 적용해보면서 학습하는 방법 이론적으로 학습하는 방법은 디자인 패턴의 개념과 원리를 이해하는 데 도움이 됩니다. 하지만 실제 프로젝트에 적용해보지 않으면 디자인 패턴을 효과적으로 사용할 수 없습니다. 따라서 디자인 패턴을 학습할 때는 이론적 학습과 실전 학습을 병행하는 것이 좋습니다. 디자인 패턴 참고 자료 디자인 패턴을 학습하기 위한 참고 자료는 다음과 같습니다. 책 Design Patterns: Elements of Reusable Object-Oriented Software by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides Head First Design Patterns by Eric Freeman, Elisabeth Freeman, Bert Bates, Kathy Sierra, and Steve McConnell 강좌 Design Patterns in Python by Corey Schafer Design Patterns in Java by John Purcell 디자인 패턴은 소프트웨어 개발에 있어 필수적인 기술입니다. 디자인 패턴을 잘 이해하고 사용하면 코드의 품질과 효율성을 크게 높일 수 있습니다. 오늘 소개해드린 내용을 바탕으로 디자인 패턴에 대한 이해를 넓혀나가시기 바랍니다. 감사합니다.
Lighthouse
🤨😘👍❤️
4