KR_Profiling - somaz94/python-study GitHub Wiki

Python ์„ฑ๋Šฅ ํ”„๋กœํŒŒ์ผ๋ง


1๏ธโƒฃ cProfile ์‚ฌ์šฉํ•˜๊ธฐ

cProfile์€ Python ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ํฌํ•จ๋œ ๊ฐ•๋ ฅํ•œ ํ”„๋กœํŒŒ์ผ๋ง ๋„๊ตฌ์ด๋‹ค.

import cProfile
import pstats
import io

def fibonacci(n):
    if n < 2:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

# ๊ธฐ๋ณธ ํ”„๋กœํŒŒ์ผ๋ง ์‹คํ–‰
def basic_profiling():
    profiler = cProfile.Profile()
    profiler.enable()
    
    # ํ…Œ์ŠคํŠธํ•  ์ฝ”๋“œ
    result = fibonacci(30)
    
    profiler.disable()
    stats = pstats.Stats(profiler).sort_stats('cumulative')
    stats.print_stats(20)  # ์ƒ์œ„ 20๊ฐœ ํ•ญ๋ชฉ๋งŒ ์ถœ๋ ฅ
    
    # ๊ฒฐ๊ณผ๋ฅผ ํŒŒ์ผ๋กœ ์ €์žฅ
    stats.dump_stats('profile.stats')
    return result

# ์ปจํ…์ŠคํŠธ ๋งค๋‹ˆ์ €๋ฅผ ์‚ฌ์šฉํ•œ ํ”„๋กœํŒŒ์ผ๋ง
def context_manager_profiling():
    result = None
    with cProfile.Profile() as pr:
        result = fibonacci(30)
    
    s = io.StringIO()
    ps = pstats.Stats(pr, stream=s).sort_stats('tottime')
    ps.print_stats(10)
    print(s.getvalue())
    return result

# ํ•จ์ˆ˜ ์ง์ ‘ ํ”„๋กœํŒŒ์ผ๋ง
def profile_function():
    cProfile.run('fibonacci(30)', 'profile.stats')
    # ๊ฒฐ๊ณผ ๋ถ„์„
    stats = pstats.Stats('profile.stats')
    stats.strip_dirs().sort_stats('cumtime').print_stats(10)

# ๊ฒฐ๊ณผ ํ•„ํ„ฐ๋ง ๋ฐ ์‹œ๊ฐํ™”
def analyze_profile_results():
    stats = pstats.Stats('profile.stats')
    
    # ํ˜ธ์ถœ ์‹œ๊ฐ„์ด 0.1์ดˆ ์ด์ƒ์ธ ํ•จ์ˆ˜๋งŒ ํ‘œ์‹œ
    stats.strip_dirs().sort_stats('cumtime').print_stats(.1)
    
    # ํŠน์ • ํ•จ์ˆ˜๋งŒ ์„ ํƒํ•ด์„œ ํ‘œ์‹œ
    stats.print_callers('fibonacci')
    
    # ํ˜ธ์ถœ์ž ์ •๋ณด ํ‘œ์‹œ
    stats.print_callees('fibonacci')
    
    # ๋‹ค์–‘ํ•œ ์ •๋ ฌ ๋ฐฉ์‹
    stats.sort_stats('ncalls').print_stats(5)  # ํ˜ธ์ถœ ํšŸ์ˆ˜
    stats.sort_stats('tottime').print_stats(5)  # ์ˆœ์ˆ˜ ์‹คํ–‰ ์‹œ๊ฐ„
    stats.sort_stats('cumtime').print_stats(5)  # ๋ˆ„์  ์‹คํ–‰ ์‹œ๊ฐ„

if __name__ == "__main__":
    basic_profiling()
    # context_manager_profiling()
    # profile_function()
    # analyze_profile_results()

โœ… ํŠน์ง•:

  • ํ•จ์ˆ˜ ํ˜ธ์ถœ ํšŸ์ˆ˜ ๋ฐ ํ˜ธ์ถœ ๊ด€๊ณ„ ์ถ”์ 
  • ๋ˆ„์  ๋ฐ ์ˆœ์ˆ˜ ์‹คํ–‰ ์‹œ๊ฐ„ ์ธก์ •
  • ์—ฌ๋Ÿฌ ์ •๋ ฌ ๋ฐฉ์‹์œผ๋กœ ๊ฒฐ๊ณผ ๋ถ„์„ ๊ฐ€๋Šฅ
  • ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ์ถ”๊ฐ€ ์„ค์น˜ ๋ถˆํ•„์š”
  • ๊ฒฐ๊ณผ๋ฅผ ํŒŒ์ผ๋กœ ์ €์žฅํ•˜์—ฌ ํ›„์† ๋ถ„์„ ์ง€์›
  • ๋‹ค์–‘ํ•œ ์‚ฌ์šฉ ๋ฐฉ์‹ (ํ•จ์ˆ˜, ์ปจํ…์ŠคํŠธ ๋งค๋‹ˆ์ €)
  • ํ˜ธ์ถœ ๊ทธ๋ž˜ํ”„ ์‹œ๊ฐํ™” ๋„๊ตฌ์™€ ํ†ตํ•ฉ ๊ฐ€๋Šฅ
  • ๋‚ฎ์€ ์˜ค๋ฒ„ํ—ค๋“œ๋กœ ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ๋„ ์‚ฌ์šฉ ๊ฐ€๋Šฅ


2๏ธโƒฃ line_profiler ์‚ฌ์šฉํ•˜๊ธฐ

line_profiler๋Š” ์ฝ”๋“œ์˜ ๊ฐ ๋ผ์ธ๋ณ„ ์‹คํ–‰ ์‹œ๊ฐ„์„ ์ •๋ฐ€ํ•˜๊ฒŒ ์ธก์ •ํ•˜๋Š” ์ „๋ฌธ ํ”„๋กœํŒŒ์ผ๋ง ๋„๊ตฌ์ด๋‹ค.

# ๋จผ์ € ์„ค์น˜: pip install line_profiler
from line_profiler import LineProfiler
import numpy as np
import time

# ํ”„๋กœํŒŒ์ผ๋งํ•  ํ•จ์ˆ˜๋ฅผ ์ •์˜
def process_data(data):
    """๋Œ€๋Ÿ‰์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ํ•จ์ˆ˜"""
    result = []
    # ๋ฐ์ดํ„ฐ ํ•„ํ„ฐ๋ง
    filtered_data = [item for item in data if item > 0]
    
    # ๋ฐ์ดํ„ฐ ๋ณ€ํ™˜
    for item in filtered_data:
        # ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฌ๋Š” ์ž‘์—… ์‹œ๋ฎฌ๋ ˆ์ด์…˜
        time.sleep(0.001)
        processed = item * 2
        result.append(processed)
    
    # ๊ฒฐ๊ณผ ์ •๋ ฌ ๋ฐ ๊ณ„์‚ฐ
    result.sort()
    total = sum(result)
    average = total / len(result) if result else 0
    
    # NumPy ์‚ฌ์šฉ ์—ฐ์‚ฐ
    np_array = np.array(result)
    std_dev = np.std(np_array) if len(np_array) > 0 else 0
    
    return {
        'filtered_count': len(filtered_data),
        'result_count': len(result),
        'total': total,
        'average': average,
        'std_dev': std_dev
    }

# ํ•จ์ˆ˜ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๋ฐฉ์‹
@profile  # ์ฐธ๊ณ : ์ด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” ์‹คํ–‰์‹œ kernprof์— ์˜ํ•ด ์ธ์‹๋จ
def process_with_decorator(data):
    """๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋กœ ํ”„๋กœํŒŒ์ผ๋ง๋˜๋Š” ํ•จ์ˆ˜"""
    return process_data(data)

# ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฐฉ์‹์œผ๋กœ ํ”„๋กœํŒŒ์ผ๋ง ์„ค์ •
def manual_profiling():
    # ํ”„๋กœํŒŒ์ผ๋Ÿฌ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
    profiler = LineProfiler()
    
    # ํ”„๋กœํŒŒ์ผ๋งํ•  ํ•จ์ˆ˜ ์ถ”๊ฐ€
    profiler.add_function(process_data)
    
    # ํ…Œ์ŠคํŠธ ๋ฐ์ดํ„ฐ ์ƒ์„ฑ (์ผ๋ถ€ ์Œ์ˆ˜ ํฌํ•จ)
    data = list(range(-5000, 5000))
    
    # ํ”„๋กœํŒŒ์ผ๋ง ์‹คํ–‰
    profiler.runcall(process_data, data)
    
    # ๊ฒฐ๊ณผ ์ถœ๋ ฅ
    profiler.print_stats(output_unit=1e-3)  # ๋ฐ€๋ฆฌ์ดˆ ๋‹จ์œ„๋กœ ์ถœ๋ ฅ
    
    # ๊ฒฐ๊ณผ๋ฅผ ํŒŒ์ผ๋กœ ์ €์žฅ
    with open('line_profile_results.txt', 'w') as f:
        profiler.print_stats(stream=f, output_unit=1e-3)
    
    # HTML ํ˜•์‹์œผ๋กœ ์ €์žฅ (์‹œ๊ฐ์  ๋ถ„์„์— ์œ ์šฉ)
    profiler.dump_stats('line_profile.lprof')
    
# ์—ฌ๋Ÿฌ ํ•จ์ˆ˜ ๋™์‹œ ํ”„๋กœํŒŒ์ผ๋ง
def multi_function_profiling():
    # ์ถ”๊ฐ€ ํ•จ์ˆ˜ ์ •์˜
    def helper_function(data):
        """๋ฐ์ดํ„ฐ ์ „์ฒ˜๋ฆฌ ํ•จ์ˆ˜"""
        return [x for x in data if isinstance(x, (int, float))]
    
    def another_function(data):
        """๋‹ค๋ฅธ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ํ•จ์ˆ˜"""
        if not data:
            return []
        return [x ** 2 for x in data]
    
    # ํ”„๋กœํŒŒ์ผ๋Ÿฌ ์„ค์ •
    profiler = LineProfiler()
    profiler.add_function(process_data)
    profiler.add_function(helper_function)
    profiler.add_function(another_function)
    
    # ์‹คํ–‰ ์ฝ”๋“œ ์ž‘์„ฑ
    def main_function():
        data = list(range(-100, 100))
        cleaned_data = helper_function(data)
        processed_data = process_data(cleaned_data)
        squared_data = another_function(cleaned_data)
        return processed_data, squared_data
    
    # ํ”„๋กœํŒŒ์ผ๋ง ์‹คํ–‰
    profiler.runcall(main_function)
    profiler.print_stats()

if __name__ == "__main__":
    manual_profiling()
    # multi_function_profiling()
    
    # ์ปค๋งจ๋“œ๋ผ์ธ์—์„œ ์‹คํ–‰ ์‹œ:
    # python -m kernprof -l script_name.py
    # python -m line_profiler script_name.py.lprof

โœ… ํŠน์ง•:

  • ์ฝ”๋“œ ๋ผ์ธ๋ณ„ ์ •๋ฐ€ํ•œ ์‹คํ–‰ ์‹œ๊ฐ„ ์ธก์ •
  • CPU ์‹œ๊ฐ„ ๋ฐ ํžˆํŠธ ์นด์šดํŠธ ์ƒ์„ธ ๋ถ„์„
  • ๋ณ‘๋ชฉ ํ˜„์ƒ์ด ์ •ํ™•ํžˆ ์–ด๋А ๋ผ์ธ์—์„œ ๋ฐœ์ƒํ•˜๋Š”์ง€ ์‹๋ณ„
  • ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๋˜๋Š” ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฐฉ์‹์œผ๋กœ ์œ ์—ฐํ•˜๊ฒŒ ์‚ฌ์šฉ
  • ๊ฒฐ๊ณผ๋ฅผ ๋‹ค์–‘ํ•œ ํ˜•์‹(ํ…์ŠคํŠธ, HTML)์œผ๋กœ ์ถœ๋ ฅ
  • ์—ฌ๋Ÿฌ ํ•จ์ˆ˜๋ฅผ ๋™์‹œ์— ํ”„๋กœํŒŒ์ผ๋งํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ
  • ์‹œ๊ฐ์  ๋ถ„์„์„ ์œ„ํ•œ ๊ฒฐ๊ณผ ํŒŒ์ผ ์ƒ์„ฑ
  • ๋งˆ์ดํฌ๋กœ์ดˆ ๋‹จ์œ„์˜ ๊ณ ์ •๋ฐ€ ์ธก์ • ์ง€์›


3๏ธโƒฃ memory_profiler ์‚ฌ์šฉํ•˜๊ธฐ

memory_profiler๋Š” Python ์ฝ”๋“œ์˜ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์„ ๋ผ์ธ๋ณ„๋กœ ์ธก์ •ํ•˜๊ณ  ๋ถ„์„ํ•˜๋Š” ๋„๊ตฌ์ด๋‹ค.

# ๋จผ์ € ์„ค์น˜: pip install memory_profiler
from memory_profiler import profile
import numpy as np
import matplotlib.pyplot as plt
from functools import lru_cache
import gc
import os
import tempfile

# ๋ผ์ธ๋ณ„ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰ ์ธก์ •
@profile
def memory_heavy_function():
    """๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” ํ•จ์ˆ˜ ์˜ˆ์‹œ"""
    results = []
    
    # ๋Œ€์šฉ๋Ÿ‰ ๋ฆฌ์ŠคํŠธ ์ƒ์„ฑ
    print("๋Œ€์šฉ๋Ÿ‰ ๋ฆฌ์ŠคํŠธ ์ƒ์„ฑ")
    big_list = [i for i in range(1000000)]
    results.append(sum(big_list))
    
    # ๋”•์…”๋„ˆ๋ฆฌ ์ƒ์„ฑ
    print("๋”•์…”๋„ˆ๋ฆฌ ์ƒ์„ฑ")
    big_dict = {i: str(i) for i in range(100000)}
    results.append(len(big_dict))
    
    # NumPy ๋ฐฐ์—ด ์ƒ์„ฑ
    print("NumPy ๋ฐฐ์—ด ์ƒ์„ฑ")
    big_array = np.random.random((1000, 1000))
    results.append(big_array.mean())
    
    # ์ค‘์ฒฉ ๋ฆฌ์ŠคํŠธ
    print("์ค‘์ฒฉ ๋ฆฌ์ŠคํŠธ ์ƒ์„ฑ")
    nested_list = [[i for i in range(1000)] for _ in range(100)]
    results.append(sum(sum(nested_list, [])))
    
    # ๋ฌธ์ž์—ด ์กฐ์ž‘
    print("๋ฌธ์ž์—ด ์กฐ์ž‘")
    text = "hello" * 100000
    results.append(len(text))
    
    # ๋ฆฌ์†Œ์Šค ์ •๋ฆฌ (๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ)
    print("๋ฆฌ์†Œ์Šค ์ •๋ฆฌ")
    del big_list, big_dict, big_array, nested_list, text
    gc.collect()  # ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰์…˜ ๊ฐ•์ œ ์‹คํ–‰
    
    return results

# ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ํŒจํ„ด ์˜ˆ์ œ
class DataNode:
    """๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๋ฅผ ์‹œ์—ฐํ•˜๊ธฐ ์œ„ํ•œ ํด๋ž˜์Šค"""
    _cache = {}  # ํด๋ž˜์Šค ๋ณ€์ˆ˜๋กœ ๋ชจ๋“  ์ธ์Šคํ„ด์Šค๊ฐ€ ๊ณต์œ 
    
    def __init__(self, name, data):
        self.name = name
        self.data = data
        # ์ž๊ธฐ ์ž์‹ ์„ ์บ์‹œ์— ์ €์žฅ (๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ํŒจํ„ด)
        DataNode._cache[name] = self
    
    @classmethod
    def clear_cache(cls):
        cls._cache.clear()

@profile
def memory_leak_demo():
    """๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ์‹œ์—ฐ"""
    # ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰ํ„ฐ ์„ค์ •
    gc.disable()  # ์‹œ์—ฐ์„ ์œ„ํ•ด ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰์…˜ ๋น„ํ™œ์„ฑํ™”
    
    print("1. ์ดˆ๊ธฐ ์ƒํƒœ")
    
    print("2. ๊ฐ์ฒด ์ƒ์„ฑ ์‹œ์ž‘")
    # ๋ฉ”๋ชจ๋ฆฌ์— ์ง€์†์ ์œผ๋กœ ๋‚จ๋Š” ๊ฐ์ฒด ์ƒ์„ฑ
    for i in range(1000):
        DataNode(f"node_{i}", np.random.random((100, 100)))
    
    print("3. ๋ช…์‹œ์ ์ธ ์ฐธ์กฐ ์ œ๊ฑฐ")
    # ๋กœ์ปฌ ์ฐธ์กฐ๋Š” ์‚ฌ๋ผ์ง€์ง€๋งŒ ํด๋ž˜์Šค ์บ์‹œ์— ๋‚จ์•„์žˆ์Œ
    
    print("4. ๋ฉ”๋ชจ๋ฆฌ ์ •๋ฆฌ ์‹œ๋„")
    gc.collect()  # ์ˆ˜๋™์œผ๋กœ ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰์…˜ ์‹คํ–‰
    
    print("5. ์บ์‹œ ์ •๋ฆฌ")
    DataNode.clear_cache()  # ์บ์‹œ ์ •๋ฆฌํ•˜์—ฌ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ํ•ด๊ฒฐ
    gc.collect()
    
    gc.enable()  # ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰ํ„ฐ ๋‹ค์‹œ ํ™œ์„ฑํ™”
    return "์™„๋ฃŒ"

# ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋‹ˆํ„ฐ๋ง ๋„๊ตฌ
def monitor_memory_usage(func, *args, **kwargs):
    """ํ•จ์ˆ˜ ์‹คํ–‰ ์ค‘ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰ ๋ชจ๋‹ˆํ„ฐ๋ง"""
    import time
    from memory_profiler import memory_usage
    
    # ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰ ์ธก์ •
    mem_usage = []
    
    def recorder():
        # 0.1์ดˆ ๊ฐ„๊ฒฉ์œผ๋กœ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰ ๊ธฐ๋ก
        mem_usage.append(memory_usage(os.getpid(), interval=0.1, timeout=1))
    
    import threading
    t = threading.Thread(target=recorder)
    t.daemon = True
    
    # ์ธก์ • ์‹œ์ž‘
    t.start()
    start_time = time.time()
    result = func(*args, **kwargs)
    elapsed = time.time() - start_time
    
    # ์ธก์ • ๊ฒฐ๊ณผ ๊ฐ€์‹œํ™”
    if mem_usage:
        # ํ‰ํƒ„ํ™”
        all_measurements = [item for sublist in mem_usage for item in sublist]
        
        plt.figure(figsize=(10, 6))
        plt.plot(all_measurements)
        plt.title(f'{func.__name__} ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰')
        plt.xlabel('์‹œ๊ฐ„ (0.1์ดˆ ๋‹จ์œ„)')
        plt.ylabel('๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰ (MB)')
        plt.grid(True)
        plt.savefig(f'{func.__name__}_memory_profile.png')
        plt.close()
        
        print(f"์ตœ๋Œ€ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰: {max(all_measurements):.2f} MB")
        print(f"ํ‰๊ท  ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰: {sum(all_measurements)/len(all_measurements):.2f} MB")
    
    print(f"์‹คํ–‰ ์‹œ๊ฐ„: {elapsed:.2f} ์ดˆ")
    return result

# ๋Œ€์šฉ๋Ÿ‰ ํŒŒ์ผ ์ฒ˜๋ฆฌ ์˜ˆ์‹œ
@profile
def process_large_file():
    """๋Œ€์šฉ๋Ÿ‰ ํŒŒ์ผ์„ ๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ์ ์œผ๋กœ ์ฒ˜๋ฆฌ"""
    # ํ…Œ์ŠคํŠธ์šฉ ๋Œ€์šฉ๋Ÿ‰ ํŒŒ์ผ ์ƒ์„ฑ
    with tempfile.NamedTemporaryFile(mode='w+', delete=False) as temp_file:
        file_path = temp_file.name
        # ์•ฝ 100MB ํฌ๊ธฐ์˜ ํŒŒ์ผ ์ƒ์„ฑ
        for i in range(5_000_000):
            temp_file.write(f"{i},{i*2},{i*3}\n")
    
    print(f"ํŒŒ์ผ ์ƒ์„ฑ ์™„๋ฃŒ: {file_path}")
    
    # ๋น„ํšจ์œจ์ ์ธ ๋ฐฉ์‹ (์ „์ฒด ํŒŒ์ผ์„ ๋ฉ”๋ชจ๋ฆฌ์— ๋กœ๋“œ)
    def inefficient_read():
        print("๋น„ํšจ์œจ์  ๋ฐฉ์‹: ์ „์ฒด ํŒŒ์ผ ๋กœ๋“œ")
        with open(file_path, 'r') as f:
            data = f.readlines()  # ์ „์ฒด ํŒŒ์ผ์„ ๋ฉ”๋ชจ๋ฆฌ์— ๋กœ๋“œ
        return len(data)
    
    # ํšจ์œจ์ ์ธ ๋ฐฉ์‹ (๋ผ์ธ๋ณ„ ์ฒ˜๋ฆฌ)
    def efficient_read():
        print("ํšจ์œจ์  ๋ฐฉ์‹: ๋ผ์ธ๋ณ„ ์ฒ˜๋ฆฌ")
        count = 0
        total = 0
        with open(file_path, 'r') as f:
            for line in f:  # ํ•œ ๋ฒˆ์— ํ•œ ๋ผ์ธ์”ฉ ์ฒ˜๋ฆฌ
                values = line.strip().split(',')
                if values and len(values) >= 3:
                    total += int(values[2])
                count += 1
        return count, total
    
    # ๋‘ ๋ฐฉ์‹์˜ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰ ๋น„๊ต
    try:
        # ๋น„ํšจ์œจ์  ๋ฐฉ์‹ ์‹คํ–‰ (์ฃผ์˜: ๋ฉ”๋ชจ๋ฆฌ ๋ถ€์กฑ ๊ฐ€๋Šฅ์„ฑ ์žˆ์Œ)
        # inefficient_count = inefficient_read()
        # print(f"๋น„ํšจ์œจ์  ๋ฐฉ์‹์œผ๋กœ ์ฝ์€ ๋ผ์ธ ์ˆ˜: {inefficient_count}")
        
        # ํšจ์œจ์  ๋ฐฉ์‹ ์‹คํ–‰
        efficient_count, total = efficient_read()
        print(f"ํšจ์œจ์  ๋ฐฉ์‹์œผ๋กœ ์ฝ์€ ๋ผ์ธ ์ˆ˜: {efficient_count}, ํ•ฉ๊ณ„: {total}")
    finally:
        # ์ž„์‹œ ํŒŒ์ผ ์‚ญ์ œ
        try:
            os.unlink(file_path)
            print(f"์ž„์‹œ ํŒŒ์ผ ์‚ญ์ œ ์™„๋ฃŒ: {file_path}")
        except:
            pass
    
    return "ํŒŒ์ผ ์ฒ˜๋ฆฌ ์™„๋ฃŒ"

if __name__ == "__main__":
    # ๊ธฐ๋ณธ ๋ฉ”๋ชจ๋ฆฌ ํ”„๋กœํŒŒ์ผ๋ง
    # memory_heavy_function()
    
    # ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ์‹œ์—ฐ
    # memory_leak_demo()
    
    # ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋‹ˆํ„ฐ๋ง
    # monitor_memory_usage(memory_heavy_function)
    
    # ๋Œ€์šฉ๋Ÿ‰ ํŒŒ์ผ ์ฒ˜๋ฆฌ
    # process_large_file()
    
    # ๋‹ค์–‘ํ•œ ๋ฐฉ์‹์˜ ๋ฉ”๋ชจ๋ฆฌ ํ”„๋กœํŒŒ์ผ๋ง
    # python -m memory_profiler script_name.py
    pass

โœ… ํŠน์ง•:

  • ์ฝ”๋“œ ๊ฐ ๋ผ์ธ์˜ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰ ์ •๋ฐ€ ์ธก์ •
  • ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ํŒจํ„ด ํƒ์ง€ ๋ฐ ๋ถ„์„
  • ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๋˜๋Š” ๋ช…๋ น์ค„ ๋„๊ตฌ๋กœ ๊ฐ„ํŽธํ•˜๊ฒŒ ์‚ฌ์šฉ
  • ๋Œ€์šฉ๋Ÿ‰ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ์ตœ์ ํ™”์— ์œ ์šฉ
  • ์‹ค์‹œ๊ฐ„ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰ ๋ชจ๋‹ˆํ„ฐ๋ง ๊ธฐ๋Šฅ
  • ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰ ๊ทธ๋ž˜ํ”„ ์‹œ๊ฐํ™” ์ง€์›
  • ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰์…˜ ๋ฐ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ์ „๋žต ๊ฐœ๋ฐœ
  • ๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ์ ์ธ ์ฝ”๋“œ ์ž‘์„ฑ์— ํ•„์ˆ˜ ๋„๊ตฌ


โš ๏ธ **GitHub.com Fallback** โš ๏ธ