728x90

docstring이란

docstring은 파이썬 코드 내에 있는 문서화 문자열로, 함수, 클래스, 모듈 등의 정의 바로 다음에 나타남

이 문자열은 해당 객체의 역할, 사용법, 매개변수 설명, 반환값 설명 등을 제공하여 코드를 이해하고 사용하는 데 도움이 됨

PEP 257이란

PEP 257은 파이썬 코드의 docstring의 포맷과 사용법에 관한 가이드라인을 제시한 문서

PEP 257의 주요 내용

  1. 첫 번째 줄 (요약) : docstring의 첫 번째 줄은 해당 객체(함수, 클래스 등)의 요약 설명을 제공해야 함
  2. 두 번째 줄 (빈 줄) : 첫 번째 줄 이후에는 빈 줄을 하나 넣어야 함
  3. 자세한 설명 : 이어지는 부분에서는 자세한 설명이 제공되어야 함
  4. 매개변수 설명 : 함수의 매개변수에 대한 설명을 포함해야 함
  5. 반환값 설명 : 함수의 반환값에 대한 설명을 포함해야 함

PEP 257은 명확하고 이해하기 쉬운 문서에 대한 표준을 제시하기 때문에, PEP 257을 따르면 새로운 개발자들이 코드를 이해하고 활용하기 쉽도록 도와주며 코드의 유지 보수를 용이하게 함

PEP 257을 준수한 docstring 예시

def add(x, y):
    """
    두 숫자의 합을 계산하는 함수

    :param x: 첫 번째 숫자
    :type x: int or float
    :param y: 두 번째 숫자
    :type y: int or float
    :return: 두 숫자의 합
    :rtype: int or float
    """
    return x + y
728x90

'Python' 카테고리의 다른 글

Python 날짜 시간 다루기 (feat. datetime)  (0) 2024.04.12
[작성중] Python 문서화 (feat. sphinx)  (0) 2024.04.12
Python ZeroMQ  (0) 2024.04.11
asyncio를 이용한 Python 비동기 프로그래밍  (0) 2024.04.10
Python websocket  (0) 2024.04.08
728x90

ZeroMQ란

ZeroMQ는 Zero Message Queue의 약자로, 고성능 경량 메시징 라이브러리

주로 메시지 큐, 분산 컴퓨팅, 백그라운드 작업 등의 작업을 수행하는 데 사용됨

ZeroMQ는 소켓을 사용하여 메시지를 전송하고, 여러 패턴 (pub-sub, req-rep 등)을 지원하여 유연성을 제공

파이썬에서는 pyzmq라이브러리를 통해 ZeroMQ를 사용할 수 있어 파이썬 애플리케이션에서 효율적이고 확장 가능한 분산 시스템을 구축할 수 있음

ZeroMQ의 장점

  • 가벼움
    ZeroMQ는 경량 메시지 패싱 라이브러리이므로, 추가적인 오버헤드 없이 빠르고 효율적인 통신 제공
  • 다양한 패턴 지원
    ZeroMQ는 다양한 통신 패턴을 지원하여 다양한 분산 시스템 아키텍처 구축 가능
    PUB-SUB, REQ-REP, PUSH-PULL 등의 패턴을 사용하여 쉽게 메시지 큐, 분산 작업 구현 가능
  • 다양한 언어 지원
    ZeroMQ는 C, C++, Python, Java, Go, Ruby 등 다양한 프로그래밍 언어에서 사용할 수 있어 다양한 환경에서의 통합 및 상호 운용성을 향상함
  • 유연성
    ZeroMQ는 유연한 구성 및 사용법을 제공하여 다양한 설정 옵션을 통해 사용자가 필요에 맞게 구성할 수 있음
  • 분산 시스템 구축 용이성
    ZeroMQ를 사용하면 복잡한 분산 시스템을 비교적 쉽게 구축할 수 있음
    다양한 컴포넌트 간의 통신을 표준화된 패턴을 사용하여 관리하기 용이함
  • 확장성
    ZeroMQ는 고성능 및 확장 가능한 아키텍처를 지원하므로, 대규모 시스템에서도 잘 동작함
  • 안정성
    ZeroMQ는 오랜 기간 동안 널리 사용되어 왔으며, 안정성이 검증됨
    또한 풍부한 커뮤니티 및 문서 지원을 통해 문제 발생 시 해결할 수 있음

ZeroMQ 사용 예시

Publisher와 Subscriber 두 개의 코드를 작성해야 함

ZeroMQ의 Publisher-Subscriber 모델에 대한 내용은 여기를 참고

 

1. 설치

pip install pyzmq

 

2. Publisher 코드 작성

import zmq
import time

context = zmq.Context()
socket = context.socket(zmq.PUB)
socket.bind("tcp://*:5555")

while True:
    message = "Update: " + str(time.time())
    socket.send_string(message)
    time.sleep(1)

 

3. Subscriber 코드 작성

import zmq

context = zmq.Context()
socket = context.socket(zmq.SUB)
socket.connect("tcp://localhost:5555")
socket.subscribe(b"")

while True:
    message = socket.recv_string()
    print("Received message:", message)

 

4. 실행

Publisher를 먼저 실행하고, Subscriber를 실행

발행자가 주기적으로 메시지를 발행하고, 구독자가 이를 구독하여 수신하는 것을 확인할 수 있음

참고

pyzmq 공식 문서 : https://learning-0mq-with-pyzmq.readthedocs.io/en/latest/pyzmq/pyzmq.html

728x90

'Python' 카테고리의 다른 글

[작성중] Python 문서화 (feat. sphinx)  (0) 2024.04.12
Python 문서화 (feat. PEP 257)  (0) 2024.04.11
asyncio를 이용한 Python 비동기 프로그래밍  (0) 2024.04.10
Python websocket  (0) 2024.04.08
Python 루틴, 서브루틴, 코루틴  (1) 2024.04.04
728x90

동기 vs 비동기

일반적인 동기식 프로그래밍에서는 작업이 순차적으로 실행되며, 한 작업이 완료될 때까지 다음 작업을 기다림

반면에 비동기식 프로그래밍에서는 작업을 병렬로 실행하고, 작업이 완료될 때까지 기다리지 않고 다른 작업을 계속할 수 있음

비동기 프로그래밍은 주로 입출력이나 네트워크 작업과 같이 시간이 오래 걸리는 작업을 수행할 때 유용함

이를 통해 여러 작업을 동시에 처리할 수 있고, 시스템 자원을 효율적으로 활용할 수 있음

asyncio

asyncio는 파이썬의 비동기 프로그래밍을 지원하는 라이브러리로, 이벤트 기반의 비동기 프로그램을 작성할 때 유용함

대규모의 동시성 작업을 처리하고, 네트워크와 파일 입출력을 효율적으로 다룰 수 있게 해 줌

asyncio의 핵심은 코루틴이벤트루프라는 개념

이벤트 루프는 비동기 작업을 관리하고 실행하는 역할이고, 코루틴은 비동기 함수로 중단된 지점에서 실행을 일시 중단하고 다른 작업을 수행한 뒤 재개할 수 있게 함

asyncio에서의 코루틴

코루틴은 async def 키워드를 사용하여 정의됨

asyncio에서는 await 키워드를 사용하여 코루틴을 호출하고 실행 

import asyncio

async def example_coroutine():
    print("Coroutine started")
    await asyncio.sleep(1)
    print("Coroutine finished")

async def main():
    await example_coroutine()

asyncio.run(main())

asyncio에서의 이벤트 루프

asyncio에서 이벤트 루프는 비동기 작업을 관리하고 실행하는 핵심 요소

이벤트 루프는 이벤트를 감지하고 처리하는 무한 루프로, 비동기 작업을 실행하고 완료될 때까지 대기하는 역할을 함

이를 통해 여러 비동기 작업을 동시에 실행하고, 작업이 완료될 때까지 기다리지 않고 다른 작업을 수행할 수 있음

시간이 오래 걸리는 입출력 작업을 비동기적으로 처리하여 프로그램의 성능을 향상하는 데 유용함

 

asyncio에서는 asyncio.get_event_loop 함수를 사용하여 이벤트 루프를 얻고, asyncio.run 메서드를 사용하여 비동기 작업을 실행함

import asyncio
import aiofiles

async def write_to_file(file_name, content):
    print(f"Writing to file: {file_name}")
    async with aiofiles.open(file_name, 'w') as file:
        await file.write(content)
        print(f"Content successfully written to {file_name}")

async def main():
    file_contents = [
        ("file1.txt", "Hello, World!"),
        ("file2.txt", "Async I/O is awesome!"),
        ("file3.txt", "Python is powerful!")
    ]

    # 비동기 파일 쓰기 작업 등록
    tasks = [write_to_file(file_name, content) for file_name, content in file_contents]

    # 비동기 작업 실행
    await asyncio.gather(*tasks)

# 이벤트 루프를 생성하여 main 함수 실행
asyncio.run(main())
더보기

실행결과

Writing to file: file1.txt
Writing to file: file2.txt
Writing to file: file3.txt
Content successfully written to file1.txt
Content successfully written to file2.txt
Content successfully written to file3.txt

asyncio에서의 동시성 제어

동시성 제어는 여러 작업이 동시에 실행될 때 발생하는 문제를 관리하고 해결하는 것

경쟁 조건과 교착 상태 같은 문제를 방지하여 프로그램의 안정성을 보장함

asyncio에서는 Lock, Semaphore, Queue 등의 동시성 제어 도구를 이용하여 여러 작업 간의 상호작용을 조절하고, 동기화를 유지할 수 있음

 

Lock를 이용한 동시성 제어 예제 코드

import asyncio

async def worker(lock, task_name):
    print(f"{task_name} is trying to acquire the lock")
    async with lock:
        print(f"{task_name} has acquired the lock")
        await asyncio.sleep(1)
        print(f"{task_name} is releasing the lock")

async def main():
    # 생성된 Lock 객체
    lock = asyncio.Lock()
    # 두 개의 작업이 동시에 실행되지만, 하나의 작업만이 lock을 확보하도록 하여 동시성 제어
    await asyncio.gather(
        worker(lock, "Task 1"),
        worker(lock, "Task 2")
    )

asyncio.run(main())
더보기

실행결과

Task 1 is trying to acquire the lock
Task 1 has acquired the lock        
Task 2 is trying to acquire the lock
Task 1 is releasing the lock
Task 2 has acquired the lock
Task 2 is releasing the lock

 

Semaphore를 이용한 동시성 제어 예제 코드

import asyncio

async def worker(semaphore, task_name):
    async with semaphore:
        print(f"{task_name} is entering the semaphore")
        await asyncio.sleep(1)
        print(f"{task_name} is leaving the semaphore")

async def main():
    # Semaphore 객체 생성
    semaphore = asyncio.Semaphore(2)  # 최대 2개의 작업을 동시에 실행
    # Semaphore를 공유하는 세 개의 작업
    await asyncio.gather(
        worker(semaphore, "Task 1"),
        worker(semaphore, "Task 2"),
        worker(semaphore, "Task 3")
    )

asyncio.run(main())
더보기

실행결과

Task 1 is entering the semaphore
Task 2 is entering the semaphore
Task 1 is leaving the semaphore
Task 2 is leaving the semaphore
Task 3 is entering the semaphore
Task 3 is leaving the semaphore

 

Queue를 이용한 동시성 제어 예제 코드

import asyncio

async def producer(queue):
    for i in range(5):
        print(f"Producing {i}")
        await queue.put(i)
        await asyncio.sleep(1)

async def consumer(queue, consumer_name):
    while True:
        item = await queue.get()
        print(f"{consumer_name} consumed {item}")
        queue.task_done()

async def main():
    # 크기가 3인 Queue 생성
    queue = asyncio.Queue(maxsize=3) # 최대 3개의 작업을 동시에 실행

    # Producer와 Consumer 생성
    producer_task = asyncio.create_task(producer(queue))
    consumer_task1 = asyncio.create_task(consumer(queue, "Consumer 1"))
    consumer_task2 = asyncio.create_task(consumer(queue, "Consumer 2"))

    # Producer가 종료될 때까지 기다림
    await producer_task
    # Consumer가 모든 작업을 처리할 때까지 기다림
    await queue.join()

    # Consumer들에게 종료를 알림
    consumer_task1.cancel()
    consumer_task2.cancel()

asyncio.run(main())
더보기

실행결과

Producing 0
Consumer 1 consumed 0
Producing 1
Consumer 1 consumed 1
Producing 2
Consumer 2 consumed 2
Producing 3
Consumer 1 consumed 3
Producing 4
Consumer 2 consumed 4

728x90

'Python' 카테고리의 다른 글

Python 문서화 (feat. PEP 257)  (0) 2024.04.11
Python ZeroMQ  (0) 2024.04.11
Python websocket  (0) 2024.04.08
Python 루틴, 서브루틴, 코루틴  (1) 2024.04.04
Python multiprocessing  (0) 2024.04.04
728x90

WebSocket이란

웹소켓(WebSocket)은 양방향 통신을 제공하는 컴퓨터 통신 프로토콜 중 하나

주로 웹 브라우저와 웹 서버 간의 실시간 데이터 전송을 위해 사용됨

HTTP 프로토콜과 달리 웹소켓은 한 번의 연결로 데이터를 주고받을 수 있어서 더 효율적이며, 실시간성이 요구되는 애플리케이션에 적합함

웹소켓은 다음과 같은 특징을 가지고 있음

  • 양방향 통신: 클라이언트와 서버 간에 양방향으로 데이터를 주고받을 수 있음
  • 실시간성: HTTP와는 달리 웹소켓은 계속 연결을 유지하며, 변경사항이 발생하면 즉시 데이터를 전달할 수 있어서 실시간성이 요구되는 애플리케이션에 적합함
  • 지속적인 연결: 웹 소켓은 지속적인 연결을 유지하여, 한번 연결되면 연결은 수동으로 종료되거나 네트워크 오류가 발생할 때까지 유지됨
  • 간편한 구현: 대부분의 주요 프로그래밍 언어에는 웹소켓을 다루기 위한 라이브러리나 프레임워크가 있어서 쉽게 구현할 수 있음

Python Websockets

Python에서 웹소켓을 다루기 위해서는 보통 websockets 라이브러리를 사용

이 라이브러리를 이용하면 손쉽게 웹소켓 서버와 클라이언트를 구현할 수 있음

 

websockets 라이브러리 설치

pip install websockets

 

웹소켓 서버 작성

import asyncio
import websockets

async def echo(websocket, path):
    async for message in websocket:
        await websocket.send(message)

async def main():
    async with websockets.serve(echo, "localhost", 8765):
        await asyncio.Future()  # Serve forever.

asyncio.run(main())

위 코드는 클라이언트가 보낸 메시지를 그대로 다시 돌려주는 간단한 에코(echo) 서버를 구현한 것

 

웹소켓 클라이언트 작성

import asyncio
import websockets

async def hello():
    uri = "ws://localhost:8765"
    async with websockets.connect(uri) as websocket:
        await websocket.send("Hello, world!")
        response = await websocket.recv()
        print(response)

asyncio.run(hello())

위 코드는 서버에 "Hello, world!"라는 메시지를 보내고, 서버로부터의 응답을 받아 출력하는 웹소켓 클라이언트를 구현한 것

 

실행

먼저 서버를 실행한 다음, 클라이언트를 실행

서버와 클라이언트가 연결되면 클라이언트는 서버에 메시지를 보내고, 서버는 클라이언트로부터 받은 메시지를 다시 돌려줌

웹소켓을 사용하면 위 예제처럼 간단하게 실시간 통신을 구현할 수 있음

필요에 따라 서버와 클라이언트 코드를 수정하여 원하는 기능을 구현 가능함

참고

https://wikidocs.net/218440

728x90

'Python' 카테고리의 다른 글

Python ZeroMQ  (0) 2024.04.11
asyncio를 이용한 Python 비동기 프로그래밍  (0) 2024.04.10
Python 루틴, 서브루틴, 코루틴  (1) 2024.04.04
Python multiprocessing  (0) 2024.04.04
파이썬 사용자 정의 에러  (0) 2024.04.02
728x90

루틴(Routine)

  • 파이썬에서 루틴은 함수(function)를 가리킴
  • 일반적으로 루틴은 함수의 형태를 가지고 있으며, 코드 블록을 실행하여 특정한 작업을 수행
  • 함수를 호출하면 루틴이 실행되고, 실행이 완료되면 결과를 반환하거나 호출자에게 제어를 반환
def my_routine():
    print("This is a routine")

my_routine()  # 루틴 호출

서브루틴(Subroutine)

  • 파이썬에서 서브루틴은 함수(function)의 하위 개념으로 사용됨
  • 일반적으로 반복되는 코드를 재사용하기 위해 만들어진 함수를 가리킴
  • 다른 함수나 메소드 내에서 호출되어 실행되며, 실행이 완료되면 호출자에게 제어를 반환함
def my_subroutine():
    print("This is a subroutine")

def my_routine():
    print("Before subroutine")
    my_subroutine()  # 서브루틴 호출
    print("After subroutine")

my_routine()  # 루틴 호출

코루틴(Coroutine)

  • 파이썬에서 코루틴은 비동기 프로그래밍을 위해 사용되는 특별한 종류의 함수
  • 코루틴은 실행 중에 일시 중단되고 다시 시작될 수 있는 함수
  • 여러 번 호출될 수 있으며, 실행이 중단된 후 나중에 다시 호출되면 이전 상태를 기억하고 계속 진행함
import asyncio

# 코루틴 함수 정의
async def producer(queue, num):
    for i in range(num):
        print(f"Producing {i}")
        await queue.put(i)  # 데이터를 큐에 넣음
        await asyncio.sleep(0.5)  # 비동기 대기

async def consumer(queue):
    while True:
        data = await queue.get()  # 큐에서 데이터를 가져옴
        print(f"Consuming {data}")
        await asyncio.sleep(1)  # 비동기 대기

async def main():
    queue = asyncio.Queue()  # 비동기 큐 생성

    # producer와 consumer를 비동기적으로 실행
    await asyncio.gather(
        producer(queue, 5),
        consumer(queue)
    )

# 이벤트 루프를 생성하고 main 함수를 실행
asyncio.run(main())

이 코드에서는 async def 키워드를 사용하여 비동기 코루틴인 producer와 consumer 함수를 정의

producer 함수는 주어진 개수의 데이터를 생성하여 큐에 넣음

consumer 함수는 큐에서 데이터를 가져와서 소비함

main 함수에서는 asyncio.gather()를 사용하여 producer와 consumer를 동시에 실행하고, 이를 위해 이벤트 루프에 등록

이 코드를 실행하면 두 코루틴이 비동기적으로 실행되고, 데이터를 주고받으며 동작하는 것을 확인할 수 있음

서브루틴과 코루틴의 차이

  • 실행 흐름 제어
    • 서브루틴은 일반적인 함수처럼 호출되어 실행되고, 실행이 완료되면 호출자에게 제어를 반환
      일반적인 함수 호출과 동일한 방식으로 작동
    • 코루틴은 실행 중에 일시 중단되고 다시 시작될 수 있는 함수
      코루틴은 실행 중에 제어를 호출자에게 반환하고 다시 호출될 때 이전 상태를 기억하고 실행을 계속함
  • 동시성과 비동기성
    • 서브루틴은 동기적으로 호출되어 실행되며, 실행이 완료될 때까지 호출자는 대기
    • 코루틴은 비동기적으로 호출되어 실행되며, 실행 중에 다른 작업을 수행하거나 대기할 수 있음
      이를 통해 동시성을 지원하고 비동기 작업을 수행 가능
  • 호출 주체
    • 서브루틴은 일반적으로 호출자가 서브루틴을 호출하고 실행
      호출자는 서브루틴이 실행을 완료할 때까지 기다리고, 결과를 반환받음
    • 코루틴은 보통 이벤트 루프(Event Loop)나 다른 코루틴에 의해 호출되고 실행됨
      코루틴은 다른 코루틴이나 이벤트 루프에게 제어를 넘기고, 나중에 다시 실행됨

정리하면 서브루틴은 일반적인 함수 호출과 동일한 방식으로 실행되며, 실행이 완료될 때까지 호출자는 대기함

반면에  코루틴은 실행 중에 중단 및 재개가 가능한 비동기 함수이며, 동시성을 지원하고 호출자와 제어를 주고받는 동안 다른 작업을 수행할 수 있음

 

728x90

'Python' 카테고리의 다른 글

asyncio를 이용한 Python 비동기 프로그래밍  (0) 2024.04.10
Python websocket  (0) 2024.04.08
Python multiprocessing  (0) 2024.04.04
파이썬 사용자 정의 에러  (0) 2024.04.02
데코레이터  (0) 2024.04.01
728x90

개요

파이썬은 기본적으로 멀티스레딩을 지원하지만, Global Interpreter Lock(GIL)의 영향으로 CPU-bound 작업에서는 실제로 병렬 실행을 보장하지 못함

이에 대한 대안 중 하나가 multiprocessing

multiprocessing 모듈은 파이썬의 표준 라이브러리에 포함되어 있으며, 여러 프로세스를 사용하여 작업을 병렬로 실행할 수 있게 해 줌

multiprocessing은 별도의 프로세스를 생성하며, 각 프로세스는 별도의 메모리 공간을 가지므로 GIL의 영향을 받지 않고  병렬 처리를 지원함

이를 통해 CPU-bound 작업의 성능을 향상할 수 있음

기본 사용법

import multiprocessing

def worker(num):
    """작업을 수행하는 함수"""
    print(f'Worker: {num}')

if __name__ == '__main__':
    # 부모 프로세스 (메인 프로세스)
    # 프로세스 스포닝 (자식 프로세스 생성)
    processes = []
    for i in range(5):
        p = multiprocessing.Process(name="SubProcess", target=worker, args=(i,))
        processes.append(p)
        p.start()

    # 모든 프로세스 종료 대기
    for p in processes:
        p.join()

multiprocessing 모듈에서 프로세스 스포닝은 Process 클래스의 인스턴스를 생성한 후 start( ) 메서드를 호출하면 됨

Process 클래스의 인스턴스를 생성할 때 생성될 자식 프로세스의 이름(name)과 위함 하고자 하는 일(함수, target), 인자(args)를 전달

※ 스포닝 : 부모 프로세스가 운영체제에 요청하여 자식 프로세스를 새로 만들어내는 과정

프로세스 풀 활용

multiprocessing.Pool을 사용하면 풀 내에서 여러 작업을 병렬로 실행 가능

multiprocessing.Pool 객체를 생성할 때 processes 매개변수를 사용하여 동시에 실행할 프로세스의 수를 지정 가능 ( 만약 지정하지 않는다면 CPU 코어 수에 따라 자동으로 설정됨 )

이를 통해 동시에 몇 개의 작업을 처리할지를 유연하게 관리할 수 있음

풀이 가득 차있는 상황에서 새로운 작업이 추가되면 작업은 작업 큐에 대기하며, 만약 작업 큐에 공간이 있으면 풀 내의 프로세스가 새로운 작업을 가져와서 처리함

from multiprocessing import Pool

def worker(num):
    """작업을 수행하는 함수"""
    return f'Worker: {num}'

if __name__ == '__main__':
    with Pool(processes=3) as pool:
        results = pool.map(worker, range(5))
    print(results)

데몬 활용

일반적으로 생성한 경우 부모 프로세스는 자식 프로세스가 종료되지 않으면 종료되지 않음

하지만 multiprocessing 모듈에서 daemon=True 옵션을 사용하면 부모 프로세스가 종료될 때 자식 프로세스도 함께 종료됨

 

데몬 프로세스를 사용하여 메인 프로세스에 영향을 주지 않으면서 동작시킬 작업들을 구현할 수 있음

  • daemon=True 옵션을 주면 유용한 예시
    • 로그 감시 데몬
      시스템 로그 파일을 지속적으로 모니터링하고 변경사항을 감지하여 중요한 이벤트를 기록하는 데몬
      이 데몬은 백그라운드에서 지속적으로 실행되며, 부모 프로세스가 종료되면 함께 종료되는 것이 좋음
    • 자동 백업 프로세스
      주기적으로 파일 시스템을 스캔하여 중요한 데이터를 백업하는 데몬
      이러한 데몬은 사용자가 시스템에 로그인할 필요 없이 백그라운드에서 실행되며, 부모 프로세스가 종료되면 함께 종료되는 것이 좋음

# Daemon Process
# 메인 프로세스가 종료시 서브 프로세스도 종료됨
import multiprocessing as mp 
import time


def work():
    print("Sub Process start")
    time.sleep(5) 
    print("Sub Process end")


if __name__ == "__main__":
    print("Main Process start")
    proc = mp.Process(name="Sub Process", target=work, daemon=True)
    proc.start()
    print("Main Process end")

서브 프로세스 상태 확인 및 종료

import multiprocessing as mp 
import time

def work():
    while True:
        print("sub process is running") 
        time.sleep(1)


if __name__ == "__main__":
    p = mp.Process(target=work, name="SubProcess")
    print("Status: ", p.is_alive())

    p.start()
    print("Status: ", p.is_alive())

    time.sleep(5)   # 메인 프로세스 3초 대기
    p.kill()        # 서브 프로세스 종료
    print("Status: ", p.is_alive())

    p.join()        # 메인 프로세스는 서브 프로세스가 종료될 때까지 블록됨
    print("Status: ", p.is_alive())

 

결과

Status:  False
Status:  True
sub process is running
sub process is running
sub process is running
sub process is running
sub process is running
Status:  True
Status:  False

 

multiprocessing 사용 시 주의사항

  • 메모리 사용량이 증가할 수 있으므로 대용량 데이터 처리 시 주의 필요
  • 각 프로세스가 독립적인 메모리 공간을 가지므로 데이터를 공유하려면 명시적인 메커니즘(예: 공유 메모리, 큐 등)을 사용해야 함
import multiprocessing as mp

def worker(q):
    q.put(1) 
    q.put(2) 
    q.put(3)

if __name__ == "__main__":
    # multiprocessing.Manager().Queue()로 Queue 생성
    manager = mp.Manager()
    q = manager.Queue() 
    
    # 프로세스 생성
    processes = []
    for _ in range(3):
        p = mp.Process(target=worker, args=(q,))
        processes.append(p)
        p.start()

    # 모든 프로세스가 종료될 때까지 대기
    for p in processes:
        p.join()

    # 멀티프로세스 간에 데이터를 공유하기 위해 Queue를 사용하여 데이터를 가져옴
    results = []
    while not q.empty():
        results.append(q.get())

    print(results)

 

결과

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

 

728x90

'Python' 카테고리의 다른 글

Python websocket  (0) 2024.04.08
Python 루틴, 서브루틴, 코루틴  (1) 2024.04.04
파이썬 사용자 정의 에러  (0) 2024.04.02
데코레이터  (0) 2024.04.01
파이썬 매직 메서드  (0) 2024.03.29
728x90

사용자 정의 에러란?

파이썬에서 사용자 정의 에러는 내장된 예외 클래스(Exception 클래스를 상속한 클래스)를 확장하여 새로운 예외 클래스를 정의하는 것

이렇게 정의된 사용자 정의 에러 클래스는 프로그램에서 특정 조건이나 상황에 대한 예외를 일으킬 때 사용

사용자 정의 에러를 정의함으로써 코드의 가독성을 높이고, 예외 처리를 보다 구체적으로 할 수 있음

사용자 정의 에러 구현 방식

  1. 내장 예외 클래스(Exception 클래스를 상속)를 상속하여 새로운 클래스를 생성
  2. 클래스 내부에 필요한 추가적인 메서드나 속성을 정의할 수 있음
    예를 들어, __str__ 메서드를 재정의하여 해당 예외가 발생했을 때 출력될 문자열을 지정할 수 있음
  3. 사용자 정의 에러 클래스를 발생시키기 위해 필요한 조건이나 상황을 프로그램에서 체크하고, 그에 따라 적절한 사용자 정의 에러 객체를 생성하여 raise 키워드를 사용하여 예외를 일으킴

사용자 정의 에러 구현 예시

class UpbitError(Exception):
    """Base 에러 클래스"""
    pass 


class CreateAskError(UpbitError):
    def __str__(self):
        return "주문 요청 정보가 올바르지 않습니다."


class CreateBidError(UpbitError):
    def __str__(self):
        return "주문 요청 정보가 올바르지 않습니다."


class InsufficientFundsAsk(UpbitError):
    def __str__(self):
        return "매수/매도 가능 잔고가 부족합니다."


class InsufficientFundsBid(UpbitError):
    def __str__(self):
        return "매수/매도 가능 잔고가 부족합니다.

예시 코드에서는 UpbitError를 기반으로 여러 사용자 정의 에러 클래스를 정의하고 있음

이 코드에서는 주문 요청 정보가 올바르지 않을 때와 매수/매도 가능 잔고가 부족할 때를 처리하기 위해 각각의 사용자 정의 에러 클래스를 구현하고 있음

위에서 구현한 사용자 정의 클래스로 예외를 발생시키는 예시코드는 아래와 같음

# 예시 코드
def create_ask(order_info):
    if not is_valid_order_info(order_info):
        raise CreateAskError()

def create_bid(order_info):
    if not is_valid_order_info(order_info):
        raise CreateBidError()

def execute_trade(trade_type, order_info):
    if trade_type == 'ask':
        try:
            create_ask(order_info)
        except CreateAskError as e:
            print("에러 발생:", e)
    elif trade_type == 'bid':
        try:
            create_bid(order_info)
        except CreateBidError as e:
            print("에러 발생:", e)

def is_valid_order_info(order_info):
    # 주문 요청 정보가 유효한지 확인하는 코드
    return True  # 예시로 항상 유효하다고 가정

# 테스트
order_info = {'amount': 100, 'price': 50}
execute_trade('ask', order_info)

order_info = {'amount': 100, 'price': 50}
execute_trade('bid', order_info)

위 코드에서는 주문 요청 정보가 유효하지 않을 경우와 매수/매도 가능 잔고가 부족할 경우에 각각의 사용자 정의 에러 클래스를 발생시킴

그리고 execute_trade 함수 내에서 이러한 예외를 처리함

참고

https://wikidocs.net/126218

728x90

'Python' 카테고리의 다른 글

Python 루틴, 서브루틴, 코루틴  (1) 2024.04.04
Python multiprocessing  (0) 2024.04.04
데코레이터  (0) 2024.04.01
파이썬 매직 메서드  (0) 2024.03.29
파이썬 공부할 책 모음  (0) 2024.03.28
728x90

데코레이터란? 

데코레이터(Decorator)는 파이썬에서 함수나 클래스의 기능을 간단하게 수정하거나 확장하기 위한 기법

주로 함수를 감싸는 형태로 사용되며, 이를 통해 함수의 동작을 변경하거나 확장 가능

데코레이터 사용 방법

데코레이터는 기능을 추가하고자 하는 함수나 메서드 위에 @데코레이터함수 와 같이 사용함

이렇게 함으로써 데코레이터 함수가 해당 함수를 감싸서 새로운 동작을 추가하거나 수정할 수 있음

데코레이터 사용 예시

deco라는 데코레이터 함수를 정의하여 hello 함수에 hello 프린트 전/후로 * 20개를 출력하는 새로운 동작을 추가함

def deco(fn):
    def deco_hello():
        print("*" * 20)
        fn()
        print("*" * 20)
    return deco_hello
    
@deco
def hello():
    print("hello")
    
hello() # hello 호출

 

호출 결과

********************
hello
********************

참고

https://wikidocs.net/160127

728x90

'Python' 카테고리의 다른 글

Python multiprocessing  (0) 2024.04.04
파이썬 사용자 정의 에러  (0) 2024.04.02
파이썬 매직 메서드  (0) 2024.03.29
파이썬 공부할 책 모음  (0) 2024.03.28
파이썬 Iterable, Iterator, Generator 간단 소개와 활용 예제  (0) 2024.03.21
728x90

매직 메서드란?

매직 메서드는 파이썬의 특수한 메서드로, 던더(double underscore, __)로 시작하고 끝나는 이름을 가지고 있음

특정한 문법이나 동작을 제공하거나 클래스의 특정한 동작을 변경하거나 확장하는 데 사용됨

매직메서드의 종류

일반적으로 사용되는 매직 메서드

  • __init__
    • 이 메서드는 클래스의 인스턴스가 생성될 때 호출되는 초기화 메서드로, 주로 객체의 속성을 초기화하고 초기 상태를 설정하는 데 사용
  • __repr__ 및 __str__
    • 객체의 문자열 표현을 반환
    • __repr__: 객체의 "official" 문자열 표현을 반환하는 메서드로, 객체를 재생성할 수 있는 문자열을 반환 (개발자용으로 사용됨)
    • __str__: 객체의 "informal" 문자열 표현을 반환하는 메서드로, 사용자에게 보여주기 위한 문자열을 반환
  • __len__
    • 객체의 길이를 반환 len() 함수가 호출될 때 사용됨
    • 리스트, 튜플, 문자열 등과 같은 내장된 시퀀스 형식들은 모두 __len__ 메서드를 구현하여 길이 반환 가능
  • __getitem__ 및 __setitem__
    • 이 두 메서드는 객체의 인덱싱 및 슬라이싱을 지원
    • __getitem__: 인덱싱 및 슬라이싱을 통해 요소를 가져오는 메서드
    • __setitem__: 인덱싱을 통해 요소에 값을 할당하는 메서드
  • __iter__ 및 __next__
    • 두 메서드는 객체의 이터레이션을 지원
    • __iter__: 이터레이터를 반환하는 메서드로, 이터레이터 프로토콜을 지원하여 객체를 반복할 수 있게 함
    • __next__: 다음 값을 반환하는 메서드로, 이터레이터의 다음 요소를 반환

연산자 오버로딩을 위한 매직 메서드

  • __add__(self, other)
    • 덧셈 연산자(+)를 오버로딩
    • 객체와 다른 객체를 더한 결과를 반환
  • __sub__(self, other)
    • 뺄셈 연산자(-)를 오버로딩
    • 객체에서 다른 객체를 뺀 결과를 반환
  • __mul__(self, other)
    • 곱셈 연산자(*)를 오버로딩
    • 객체와 다른 객체를 곱한 결과를 반환
  • __truediv__(self, other)
    • 나눗셈 연산자(/)를 오버로딩
    • 객체를 다른 객체로 나눈 결과를 반환
  • __floordiv__(self, other)
    • 나눗셈 연산자의 몫(//)를 오버로딩
    • 객체를 다른 객체로 나눈 몫을 반환
  • __mod__(self, other)
    • 나머지 연산자(%)를 오버로딩
    • 객체를 다른 객체로 나눈 나머지를 반환
  • __pow__(self, other[, modulo])
    • 거듭제곱 연산자(**)를 오버로딩
    • 객체를 다른 객체의 거듭제곱으로 계산한 결과를 반환
  • __eq__(self, other)
    • 동등성 비교 연산자(==)를 오버로딩
    • 객체가 다른 객체와 동일한지를 확인하는 데 사용
  • __lt__(self, other), __gt__(self, other), __le__(self, other), __ge__(self, other)
    • 대소 비교 연산자(<, >, <=, >=)를 오버로딩
    • 객체를 다른 객체와 비교하여 대소 관계를 확인하는 데 사용

컨텍스트 관리를 위한 매직 메서드

  • __enter__(self)
    • 컨텍스트가 시작될 때 호출되는 메서드
    • 이 메서드는 with 블록의 시작에서 호출되며, 컨텍스트 진입 시 수행해야 하는 작업을 정의
    • 일반적으로 컨텍스트 진입 시 초기화 작업이나 리소스를 할당하는 작업을 수행
    • 이 메서드는 with 문에 의해 생성된 컨텍스트 매니저를 반환
  • __exit__(self, exc_type, exc_value, traceback)
    • 컨텍스트가 종료될 때 호출되는 메서드
    • 이 메서드는 with 블록에서 예외가 발생했더라도 항상 호출
    • 컨텍스트 종료 시 정리 작업을 수행하거나 예외 처리를 위한 로직을 구현 가능
    • 만약 예외가 발생했을 경우에는 exc_type, exc_value, traceback 파라미터에 예외 정보가 전달됨

매직 메서드를 사용한 커스텀 데이터 구조 및 동작 정의 예시

class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    # 벡터의 덧셈 연산을 정의
    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y)

    # 벡터의 뺄셈 연산을 정의
    def __sub__(self, other):
        return Vector(self.x - other.x, self.y - other.y)

    # 벡터의 스칼라 곱셈 연산을 정의
    def __mul__(self, scalar):
        return Vector(self.x * scalar, self.y * scalar)

    # 벡터의 크기(길이)를 반환하는 메서드를 정의
    def __abs__(self):
        return (self.x ** 2 + self.y ** 2) ** 0.5

    # 벡터의 문자열 표현을 정의
    def __str__(self):
        return f"({self.x}, {self.y})"

# 사용 예시
v1 = Vector(1, 2)
v2 = Vector(3, 4)

print("v1 =", v1)
print("v2 =", v2)
print("v1 + v2 =", v1 + v2)  # 벡터 덧셈
print("v1 - v2 =", v1 - v2)  # 벡터 뺄셈
print("v1 * 2 =", v1 * 2)    # 스칼라 곱셈
print("|v1| =", abs(v1))     # 벡터 크기(길이)

참고

매직메서드소개 : https://wikidocs.net/83755

728x90
728x90

- 레벨업 파이썬 : https://wikidocs.net/book/4170

 

레벨업 파이썬

다른 프로그래밍 언어를 배워서 최소한의 파이썬 문법만 배워서 근근히 코딩하는 분들, 파이썬으로 처음 프로그래밍에 입문했지만 복잡한 문법은 안쓰는 분들을 위한 파이썬 중급 문법서입…

wikidocs.net

- 파이썬 강좌 : https://wikidocs.net/book/2251

 

Python 강좌.

[TOC] python에서 설치된 모듈(module)들은 `C:\Users\khjung\AppData\Local\Programs\Python\Python310\Lib\si…

wikidocs.net

- 파이썬 라이브러리 탐험 : https://wikidocs.net/book/14021

 

함께해요 파이썬 생태계

파이썬의 진정한 마스터가 되는 길은 어떤 것일까요? 수년 간 파이썬을 사용해왔다 해도, 같은 라이브러리들로만 프로젝트를 진행하다 보면, 과연 '파이썬을 잘한다'고 말하기에는 무언…

wikidocs.net

- 파이썬 틀린코드 : https://wikidocs.net/book/8131

 

파이썬 틀린코드 (Feat. 파이썬 클린코드)

# 책 소개 개발을 하다보면 여러 `코드`에 대해 마주치게 됩니다. 구조화가 되지 않아 찾기 힘든 `코드`, 문서화가 되어 있지 않은 `코드`, 전임 …

wikidocs.net

- 파이썬 클린 아키텍처 : https://wikidocs.net/book/9408

 

파이썬에 적용하는 클린 아키텍처(Clean Architectures in Python), 제2판

부제: 더 나은 소프트웨어 디자인을 위한 실용적인 접근법 저자: 레오나르도 조르다니(Leonardo Giordani) 한국어 역자: dextto (feat. ChatG…

wikidocs.net

 

728x90

+ Recent posts