Skip to content

Latest commit

ย 

History

History
149 lines (116 loc) ยท 5.88 KB

File metadata and controls

149 lines (116 loc) ยท 5.88 KB

53. ๋ธ”๋กœํ‚น I/O์˜ ๊ฒฝ์šฐ ์Šค๋ ˆ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ๋ณ‘๋ ฌ์„ฑ์„ ํ”ผํ•˜๋ผ

1. CPython

  • ํŒŒ์ด์„ ์˜ ํ‘œ์ค€ ๊ตฌํ˜„

  • 2๋‹จ๊ณ„๋กœ ๊ตฌ์„ฑ

    1. ์†Œ์Šค ์ฝ”๋“œ๋ฅผ ๊ตฌ๋ฌธ ๋ถ„์„ํ•ด์„œ ๋ฐ”์ดํŠธ์ฝ”๋“œ๋กœ ๋ณ€ํ™˜
      • 8๋น„ํŠธ ๋ช…๋ น์–ด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ €์ˆ˜์ค€ ํ”„๋กœ๊ทธ๋žจ ํ‘œํ˜„
        • 3.6 ๋ถ€ํ„ฐ 16๋น„ํŠธ ๋ช…๋ น์–ด๋ฅผ ์‚ฌ์šฉ, wordcode
    2. ๋ฐ”์ดํŠธ์ฝ”๋“œ๋ฅผ ์Šคํƒ ๊ธฐ๋ฐ˜ ์ธํ„ฐํ”„๋ฆฌํ„ฐ๋ฅผ ํ†ตํ•ด ์‹คํ–‰
      • ๋ฐ”์ดํŠธ์ฝ”๋“œ ์ธํ„ฐํ”„๋ฆฌํ„ฐ์— ์ „์—ญ ์ธํ„ฐํ”„๋ฆฌํ„ฐ ๋ฝ(GIL, Global Interpreter Lock) ์‚ฌ์šฉํ•˜์—ฌ ์ผ๊ด€์„ฑ ๊ฐ•์ œ ์œ ์ง€
      • GIL
        • ์ƒํ˜ธ ๋ฐฐ์ œ ๋ฝ
        • ๋ฎคํ…์Šค
        • ์„ ์ ํ˜• ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ๋กœ ์ธํ•ด ์˜ํ–ฅ์„ ๋ฐ›๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€
          • ํ•œ ์Šค๋ ˆ๋“œ๊ฐ€ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ์˜ ์‹คํ–‰์„ ์ค‘๊ฐ„์— ์ธํ„ฐ๋ŸฝํŠธ์‹œํ‚ค๊ณ  ์ œ์–ด๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Œ
          • ์ธํ„ฐ๋ŸฝํŠธ๊ฐ€ ์˜ˆ๊ธฐ์น˜ ๋ชปํ•œ ๋•Œ ๋ฐœ์ƒํ•˜๋ฉด ์ธํ„ฐํ”„๋ฆฌํ„ฐ์˜ ์ƒํƒœ๊ฐ€ ์˜ค์—ผ๋  ์ˆ˜ ์žˆ์Œ
        • ์—ญํ• 
          • CPython ์ž์ฒด์™€ CPython์ด ์‚ฌ์šฉํ•˜๋Š” C ํ™•์žฅ ๋ชจ๋“ˆ์ด ์‹คํ–‰๋˜๋ฉด์„œ ์ธํ„ฐ๋ŸฝํŠธ๊ฐ€ ํ•จ๋ถ€๋กœ ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€
          • ์ธํ„ฐํ”„๋ฆฌํ„ฐ ์ƒํƒœ๊ฐ€ ์ œ๋Œ€๋กœ ์œ ์ง€๋˜๊ณ  ๋ฐ”์ดํŠธ์ฝ”๋“œ ๋ช…๋ น๋“ค์ด ์ œ๋Œ€๋กœ ์‹คํ–‰๋˜๋„๋ก ๋งŒ๋“ฌ
        • side-effect
          • python ๋‹ค์ค‘ ์Šค๋ ˆ๋“œ ์ง€์›ํ•˜์ง€๋งŒ GIL๋กœ ์ธํ•ด ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ ์ค‘ ์–ด๋А ํ•˜๋‚˜๋งŒ ์ง„ํ–‰ ๊ฐ€๋Šฅ
          • ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ณ ์ž ์Šค๋ ˆ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ๋จ
  • ์ˆœ์ฐจ์  ์‹คํ–‰ ์˜ˆ์ œ

    import time
    def factorize(number):
        for i in range(1, number + 1):
            if number % i == 0:
                yield i
    
    numbers = [2139079, 1214759, 1516637, 1852285]
    start = time.time()
    
    for number in numbers:
        list(factorize(number))
    
    end = time.time()
    delta = end - start
    print(f'์ด {delta:.3f} ์ดˆ ๊ฑธ๋ฆผ')
    
    >>>
    ์ด 0.256 ์ดˆ ๊ฑธ๋ฆผ
  • ์Šค๋ ˆ๋“œ๋ฅผ ์‚ฌ์šฉํ•œ ์˜ˆ์ œ

    from threading import Thread
    
    class FactorizeThread(Thread):
        def __init__(self, number):
            super().__init__()
            self.number = number
            
        def run(self):
            self.factors = list(factorize(self.number))
    
    start = time.time()
    threads = []
    for number in numbers:
        thread = FactorizeThread(number)
        thread.start()
        threads.append(thread)
    
    for thread in threads:
        thread.join()
    end = time.time()
    delta = end - start
    print(f'์ด {delta:.3f} ์ดˆ ๊ฑธ๋ฆผ')
    
    >>>
    ์ด 0.446 ์ดˆ ๊ฑธ๋ฆผ
  • ์ˆœ์ฐจ์  ์‹คํ–‰๋ณด๋‹ค ์Šค๋ ˆ๋“œ ์‹คํ–‰์ด ๋” ์˜ค๋ž˜ ๊ฑธ๋ฆผ

    • ํ•ด๋‹น ์„œ์ ์—์„œ๋Š” 9900k ์—์„œ WSL ์ƒํƒœ์—์„œ ์‹คํ–‰ํ•œ ๊ฒฐ๊ณผ ๊ทผ์†Œํ•˜๊ฒŒ ์Šค๋ ˆ๋“œ ์‚ฌ์šฉ ์˜ˆ์ œ์˜ ์‹œ๊ฐ„์ด ๋” ๋นจ๋ž์œผ๋‚˜ ๊ฒฐ๊ตญ ์„ฑ๋Šฅํ–ฅ์ƒ์€ ์—†๋‹ค๊ณ  ๊ฐ•์กฐํ•จ
    • ๋‹ค๋ฅธ ์–ธ์–ด์— ๋น„ํ•ด ์Šค๋ ˆ๋“œ๋ฅผ ํ•˜๋‚˜์”ฉ ํ• ๋‹นํ•˜๋ฉด, ์Šค๋ ˆ๋“œ ์ƒ์„ฑ ๋ฐ ์กฐ์ •์— ๋”ฐ๋ฅธ ๋ถ€๊ฐ€ ๋น„์šฉ์ด ๋ฐœ์ƒ
    • ํ•ด๋‹น ๊ฒฐ๊ณผ๋Š” ํ‘œ์ค€ CPython ์ธํ„ฐํ”„๋ฆฌํ„ฐ์—์„œ GIL์˜ ๋ฝ ์ถฉ๋Œ๊ณผ ์Šค์ผ€์ค„๋ง ๋ถ€๊ฐ€ ๋น„์šฉ์ด ๋ฏธ์น˜๋Š” ์˜ํ–ฅ์„ ์ž˜ ๋ณด์—ฌ์ฃผ๋Š” ์˜ˆ

2. Python ์—์„œ ์Šค๋ ˆ๋“œ๋ฅผ ์ง€์›ํ•˜๋Š” ์ด์œ ๋Š”?

  • ๋‹ค์ค‘ ์Šค๋ ˆ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ”„๋กœ๊ทธ๋žจ์— ๋™์‹œ์— ์—ฌ๋Ÿฌ ์ผ์„ ํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด๊ฒŒ ๋งŒ๋“ค๊ธฐ ์‰ฌ์›€

    • ๋™์‹œ์„ฑ ์ž‘์—…์— ์Šค๋ ˆ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด GIL์— ์˜ํ•ด ์Šค๋ ˆ๋“œ ์ค‘ ํ•˜๋‚˜๋งŒ ์‹คํ–‰์ด ๋˜์ง€๋งŒ CPython ์ด ์–ด๋А ์ •๋„ ๊ท ์ผํ•˜๊ฒŒ ๊ฐ ์Šค๋ ˆ๋“œ๋ฅผ ์‹คํ–‰์‹œํ‚ค๋ฏ€๋กœ ๋‹ค์ค‘ ์Šค๋ ˆ๋“œ๋ฅผ ํ†ตํ•ด ์—ฌ๋Ÿฌ ํ•จ์ˆ˜๋ฅผ ๋™์‹œ์— ์‹คํ–‰ ๊ฐ€๋Šฅ
  • ๋ธ”๋กœํ‚น I/O ๋ฅผ ๋‹ค๋ฃจ๊ธฐ ์œ„ํ•จ

    • python ์ด ํŠน์ • system call ์„ ์‚ฌ์šฉํ•  ๋•Œ ๋ฐœ์ƒ
    • ํŒŒ์ผ read/write, network interaction, hardware ๊ฐ„ ํ†ต์‹ ๊ณผ ๊ฐ™์€ ์ž‘์—…์ด ๋ธ”๋กœํ‚น I/O ์— ์†ํ•จ
    • ์Šค๋ ˆ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์šด์˜์ฒด์ œ๊ฐ€ system call ์š”์ฒญ์— ์‘๋‹ตํ•˜๋Š” ๋ฐ ๊ฑธ๋ฆฌ๋Š” ์‹œ๊ฐ„ ๋™์•ˆ ๋‹ค๋ฅธ ์ž‘์—… ๊ฐ€๋Šฅ
  • ์ง๋ ฌ ํฌํŠธ๋ฅผ ํ†ตํ•ด ์›๊ฒฉ ์ œ์–ด ํ—ฌ๋ฆฌ์ฝฅํ„ฐ์— ์‹ ํ˜ธ๋ฅผ ๋ณด๋‚ด๋Š” ์ˆœ์ฐจ์  ์‹คํ–‰ ์˜ˆ์ œ

    import select
    import socket
    
    def slow_systemcall():
        select.select([socket.socket()], [], [], 0.1)
    
    start = time.time()
    
    for _ in range(5):
        slow_systemcall()
    end = time.time()
    delta = end - start
    print(f'์ด {delta:.3f} ์ดˆ ๊ฑธ๋ฆผ')
    
    >>>
    ์ด 0.503 ์ดˆ ๊ฑธ๋ฆผ
  • ์ง๋ ฌ ํฌํŠธ๋ฅผ ํ†ตํ•ด ์›๊ฒฉ ์ œ์–ด ํ—ฌ๋ฆฌ์ฝฅํ„ฐ์— ์‹ ํ˜ธ๋ฅผ ๋ณด๋‚ด๋Š” ์Šค๋ ˆ๋“œ ์‹คํ–‰ ์˜ˆ์ œ

    start = time.time()
    threads = []
    for _ in range(5):
        thread = Thread(target=slow_systemcall)
        thread.start()
        threads.append(thread)
    
    def compute_helicopter_location(index):
        ...
    
    for i in range(5):
        compute_helicopter_location(i)
    
    for thread in threads:
        thread.join()
    
    end = time.time()
    delta = end - start
    print(f'์ด {delta:.3f} ์ดˆ ๊ฑธ๋ฆผ')
    
    >>>
    ์ด 0.102 ์ดˆ ๊ฑธ๋ฆผ
  • slow_systemcall ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋˜๋Š” ๋™์•ˆ ํ”„๋กœ๊ทธ๋žจ์€ ์•„๋ฌด๊ฒƒ๋„ ์ž‘์—…์„ ์ง„ํ–‰ํ•˜์ง€ ๋ชปํ•จ

    • select ์‹œ์Šคํ…œ ์ฝœ์— ์˜ํ•ด ๋ธ”๋ก๋จ
    • ํ—ฌ๋ฆฌ์ฝฅํ„ฐ์— ์‹ ํ˜ธ๋ฅผ ๋ณด๋‚ด๋Š” ๋™์•ˆ ํ—ฌ๋ฆฌ์ฝฅํ„ฐ๊ฐ€ ๋‹ค์Œ์— ์–ด๋””๋กœ ์ด๋™ํ•  ์ง€ ๊ณ„์‚ฐ ๊ฐ€๋Šฅํ•ด์•ผ ํ•˜๋Š”๋ฐ ์ˆœ์ฐจ์  ์‹คํ–‰์€ ์ด๋Ÿฐ ์ž‘์—…์„ ๋™์‹œ์— ํ•˜์ง€ ๋ชปํ•จ
  • slow_systemcall ์„ ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ์—์„œ ๋”ฐ๋กœ ํ˜ธ์ถœํ•˜๋„๋ก ํ•˜์—ฌ ๋ธ”๋ก ์ž‘์—…๊ณผ python ์ž‘์—…์„ ๋™์‹œ์— ๊ฐ€๋Šฅํ•˜๋„๋ก ๊ตฌํ˜„

3. ์ •๋ฆฌ

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