Python/Python

[Python] Concurrency PDF 파일 생성 - 2

상쾌한기분 2022. 8. 12. 14:44
728x90
반응형

PDF 파일 생성

PDF 파일 생성은 비동기 I/O 작업이다. 평벙하고 쉽게 누구나처럼 그냥 함수 혹은 클래스 작성해서 반복문으로 구현할 수도 있지만,
정말로 업무가 급하고 그런게 아니라고 한다면, 빠르게 동작을 할 수 있도록 하자.

Sample Data와 Package

import random
import uuid
from threading import Thread

from faker import Faker
from fpdf import FPDF

fake = Faker()


class Person:
    # slots는 Class attr에 빠른 접근 및 제어, 적은 메모리 사용에 이점이 있다.
    __slots__ = ['name', 'age', 'location']

    def __init__(self, name: str, age: int, location: str):
        self.name = name
        self.age = age
        self.location = location

# Faker와 random 모듈로 dummy data를 생성
test_data = [Person(
    fake.name(), random.randint(1, 100), fake.address()
) for _ in range(10)]

PDF Thread, Thread Class

아래 샘플로 두가지로 구현을 했는데, 실제 서비스를 위해서는 이렇게 간단하게 끝나지 않으므로 Thread Class를 사용해서 개발을 하는 것이 좋아 보인다. 지금은...

PDF 생성이 여기서 밖에 안쓰이면 Thread Class안에서 다 구현해도 되지만 미래에 어떻게 될지 모르며 확장이나 변경에 유연해지지도 않으며 단일 책임원칙도 벗어난다. 따라서, 함수나 Builder 패턴으로 Class 구현을 해놓고 사용하는 것이 좋아 보인다.

정말 많은 수량을 다룬다고 하면 Golang으로 서비스 하자. Python 너무 느리다.

PDF Thread

def create_pdf(no: int, person: Person):
    pdf = FPDF()
    pdf.add_page()
    pdf.set_font("helvetica", size=12)
    pdf.cell(txt=f"Name : {person.name}")
    pdf.cell(txt=f"Age : {person.age}")
    pdf.cell(txt=f"Location : {person.location}")
    pdf.output(name=f"data/{uuid.uuid4()}.pdf")
    print(f"{no} is done")


threads = []
for i, person in enumerate(test_data):
    threads.append(Thread(target=create_pdf, args=(i, person,)))

for th in threads:
    th.start()

for th in threads:
    th.join()

# output
"""
0 is done
5 is done
3 is done
1 is done
6 is done
2 is done
7 is done
8 is done
4 is done
9 is done
"""

PDF Thread Class

class PDFCreator(threading.Thread):

    def __init__(self, no: int, person: Person):
        self.no = no
        self.person = person
        super().__init__()

    def run(self) -> None:
        pdf = FPDF()
        pdf.add_page()
        pdf.set_font("helvetica", size=12)
        pdf.cell(txt=f"Name : {self.person.name}")
        pdf.cell(txt=f"Age : {self.person.age}")
        pdf.cell(txt=f"Location : {self.person.location}")
        pdf.output(name=f"data/{uuid.uuid4()}.pdf")
        print(f"{self.no} is done")


threads = []
for i, person in enumerate(test_data):
    threads.append(PDFCreator(i, person))

for th in threads:
    th.start()

for th in threads:
    th.join()

"""
2 is done
0 is done
5 is done
3 is done
7 is done
4 is done
6 is done
8 is done
1 is done
9 is done
"""

단순 반복문 구현 완료 시간

Thread Class 사용 구현 완료 시간

List를 생성할 때는 create_list() 방법보다는 create_list_comprehension() 방법을 사용하도록 하자

def create_list() -> List[Something]:
    result = []
    for _ in range(x):
        result.append(Something(some, value, what))
    return result
    
    
def create_list_comprehension() -> List[Something]:
	return [result.append(Something(some, value, what)) for _ in range(x)]

 

728x90
반응형