Advanced_Python

BLAKE KIMยท2020๋…„ 7์›” 22์ผ

list comprehension๐Ÿง

  • ํ•œ ์ค„๋กœ ๋ฐ˜๋ณต๋ฌธ๊ณผ ์กฐ๊ฑด๋ฌธ์„ ๋„ฃ์€ ์ƒํƒœ๋ฅผ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๊ทธ๋Ÿฌ๋‚˜ ๊ฐ€๋…์„ฑ์ด ๋–จ์–ด์ง€๋Š” ๊ฒฝ์šฐ๋Š” ์‚ฌ์šฉํ•˜๊ธฐ ์ข‹์€ ๊ฒฝ์šฐ๋ผ๊ณ  ํ•  ์ˆ˜ ์—†๋‹ค.
  • Python์ด ์ค„ ๋‹จ์œ„๋กœ ์ฝ”๋“œ๋ฅผ ์ธ์‹ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์†๋„๊ฐ€ ๋” ๋น ๋ฅธ ๊ฒƒ์œผ๋กœ ์ƒ๊ฐ๋œ๋‹ค.

iterator๐Ÿง

  • iterator๋Š” ๊ฐ’์„ ์ฐจ๋ก€๋กœ ๊บผ๋‚ผ ์ˆ˜ ์žˆ๋Š” ๊ฐ์ฒด์ด๋‹ค.
  • iter() ๋ฉ”์†Œ๋“œ๋กœ iterator๋ฅผ ์–ป๋Š”๋‹ค.(__iter__)
  • list, tuple, range, string, dictionary, set ๋“ฑ์ด ํ•ด๋‹นํ•œ๋‹ค.
  • for๋ฌธ์„ ๊ตณ์ด ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ ๋„ next()๋ฉ”์†Œ๋“œ(__next__)๋ฅผ ํ†ตํ•ด ๋‹ค์Œ์— ํ•ด๋‹นํ•˜๋Š” ๊ฐ’์„ ๋ฐ›์•„ ์˜ฌ ์ˆ˜ ์žˆ๋‹ค. ๋‹ค์Œ์— ๋ณด๋‚ด์ค„ ๊ฐ’์ด ์—†์„ ๋•Œ๋Š” ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค. ๋•Œ๋ฌธ์— ์œ„ ์ฝ”๋“œ์—์„œ while๋ฌธ์„ ๋น ์ ธ ๋‚˜์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

generator๐Ÿง

์ œ๋„ˆ๋ ˆ์ดํ„ฐ๋Š” ์ดํ„ฐ๋ ˆ์ดํ„ฐ๋ฅผ ์ƒ์„ฑํ•ด์ฃผ๋Š” ํ•จ์ˆ˜์ด๋‹ค. ์ œ๋„ˆ๋ ˆ์ดํ„ฐ๋Š” ํ•จ์ˆ˜ ์•ˆ์—์„œ yield ํ‚ค์›Œ๋“œ๋งŒ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

def number_generator():
    yield 0
    yield 1
    yield 2
 
g = number_generator()
print(g.next()) # 0
print(g.next()) # 1
print(g.next()) # 2
print(g.next()) # StopIteration

์ด๋ฒˆ ๊ณผ์ œ๋Š” ๋‹ค์Œ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•ด๋ณด๊ณ  ๋ถ„์„ํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋ธ”๋กœ๊น…ํ•˜๋Š” ๊ณผ์ œ ์ž…๋‹ˆ๋‹ค. lazy evaluation ์ด๋ž€ ๋ฌด์—‡์ธ์ง€์™€ ์žฅ์  ๋ฐ ๋ฆฌ์ŠคํŠธ ์ปดํ”„๋ฆฌํ—จ์…˜๊ณผ์˜ ์ฐจ์ด์ ์— ๋Œ€ํ•˜์—ฌ ๋ธ”๋กœ๊น… ํ•ด์ฃผ์„ธ์š”

import time

L = [ 1,2,3]

def print_iter(iter):
    for element in iter:
        print(element)

def lazy_return(num):
    print("sleep 1s")
    time.sleep(1)
    return num

print("comprehension_list=")
comprehension_list = [ lazy_return(i) for i in L ]
print_iter(comprehension_list)

print("generator_exp=")
generator_exp = ( lazy_return(i) for i in L )
print_iter(generator_exp)

lazy evaluation

lazy evaluation์€ ๊ณ„์‚ฐ์„ ๋‚˜์ค‘์œผ๋กœ ๋ฏธ๋ฃจ๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•˜๋ฉฐ ์ด๋Š” ๋ฉ”๋ชจ๋ฆฌ์— ๋Œ€ํ•ด์„œ ์žฅ์ ์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰์‹œํ‚จ ํ›„์— return ๊ฐ’์„ ํ™œ์šฉํ•˜์ง€ ์•Š์œผ๋ฉด ๋ฉ”๋ชจ๋ฆฌ์˜ ๋‚ญ๋น„๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋  ๋•Œ๊นŒ์ง€ ๊ณ„์‚ฐ์„ ๋ฏธ๋ฃจ๊ธฐ ๋•Œ๋ฌธ์— ๋ฉ”๋ชจ๋ฆฌ ๋‚ญ๋น„๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๊ฒŒ ๋œ๋‹ค.

VS list comprehension

์ฐจ์ด์ ์„ ์„ค๋ช…ํ•˜๊ธฐ ์ „์— ์œ„์˜ ์ฝ”๋“œ ์‹คํ–‰ ๊ฒฐ๊ณผ ํ™”๋ฉด์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • list comprehension์€ lazy_return ํ•จ์ˆ˜๊ฐ€ ๋ชจ๋‘ ์‹คํ–‰๋œ ํ›„์— print_iter ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋œ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ generator๋Š” lazy_return ์‹คํ–‰ ํ›„์— for๋ฌธ์˜ ๋‹ค์Œ cycle์ด ๋ฐ”๋กœ ์‹คํ–‰๋˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์™ธ๋ถ€๋กœ ๋น ์ ธ๋‚˜์™€ ๋‹ค๋ฅธ ์ฝ”๋“œ์—๊ฒŒ ์–‘๋ณดํ•œ๋‹ค. ๊ทธ๋ ‡๊ธฐ์— print_iter ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋˜๊ณ  ๊ทธ ํ•จ์ˆ˜ ๋‚ด๋ถ€์—์„œ ๋‘ ๋ฒˆ์งธ generator ํ•จ์ˆ˜๊ฐ€ ํ•„์š”ํ•˜๊ฒŒ ๋˜์ž ๋‹ค์‹œ lazy_return ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ๋‹ค์Œ ์ž‘์—…์„ ๋ฐ˜๋ณตํ•˜๊ฒŒ ๋œ๋‹ค.
  • ์ฆ‰ generator ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋˜๋Š” ์ˆœ๊ฐ„์— ๋ฏธ๋ค„๋‘์—ˆ๋˜ ๊ณ„์‚ฐ์„ ํ•˜๊ฒŒ ๋˜๊ณ  ์ด์™€ ๋‹ฌ๋ฆฌ list comprehension์€ ๊ทธ์™€ ๊ด€๊ณ„ ์—†์ด ์šฐ์„  ๊ณ„์‚ฐ์„ ์‹œ์ž‘ํ•˜๊ณ  ๋งˆ์น˜๊ฒŒ ๋œ๋‹ค.

lambda๐Ÿง

lambda๋Š” ์ต๋ช… ํ•จ์ˆ˜์ด๋‹ค.

lambda ๋งค๊ฐœ๋ณ€์ˆ˜๋“ค: ์‹, ์ธ์ž
lambda ๋งค๊ฐœ๋ณ€์ˆ˜๋“ค: ์‹1 if ์กฐ๊ฑด์‹ else ์‹2
lambda ๋งค๊ฐœ๋ณ€์ˆ˜๋“ค: ์‹1 if ์กฐ๊ฑด์‹1 else ์‹2 if ์กฐ๊ฑด์‹2 else ์‹3

1๋ฒˆ

๋‹ค์Œ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•ด๋ณด๊ณ  print๋ฌธ์œผ๋กœ ์ถœ๋ ฅ๋˜๋Š” ์ถœ๋ ฅ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•ด๋ณด๊ณ  types ๋ชจ๋“ˆ์— LambdaType ์™ธ์—๋„ ์–ด๋–ค ํƒ€์ž…๋“ค์ด ์žˆ๋Š”์ง€ ์กฐ์‚ฌํ•ด ๋ณด์„ธ์š”.

  • ์ฝ”๋“œ
  • ์ถœ๋ ฅ ๊ฒฐ๊ณผ

types ๋ชจ๋“ˆ์— ์žˆ๋Š” type

  • types.FunctionType
  • types.LambdaType
  • types.GeneratorType
  • types.CoroutineType
  • types.AsyncGeneratorType
  • class types.CodeType(**kwargs)
  • types.CellType
  • types.MethodType
  • types.BuiltinFunctionType
  • types.BuiltinMethodType
  • types.WrapperDescriptorType
  • types.MethodWrapperType
  • types.MethodDescriptorType
  • types.ClassMethodDescriptorType
  • class types.ModuleType(name, doc=None)
  • class types.TracebackType(tb_next, tb_frame, tb_lasti, tb_lineno)
  • types.FrameType
  • types.GetSetDescriptorType
  • types.MemberDescriptorType
  • class types.MappingProxyType(mapping)

2๋ฒˆ

  • ์ฝ”๋“œ

  • ์ถœ๋ ฅ ๊ฒฐ๊ณผ

Thread๐Ÿง

1๋ฒˆ

์“ฐ๋ ˆ๋“œ ๊ณต์‹๋ฌธ์„œ์—์„œ ํ•™์Šตํ•œ ๋‚ด์šฉ์— ๋Œ€ํ•ด์„œ ์ž์œ ๋กญ๊ฒŒ ๋ธ”๋กœ๊น…(์‹คํ–‰ํ•ด๋ณธ ์˜ˆ์ œ์ฝ”๋“œ๋ฅผ ๋ถ„์„ํ•œ ๋‚ด์šฉ์„ ๋ธ”๋กœ๊น…ํ•ด๋„ ์ข‹๊ณ  ์ด๋ก ์ ์ธ ๋‚ด์šฉ์„ ๋ธ”๋กœ๊น…ํ•ด๋„ ์ข‹์Šต๋‹ˆ๋‹ค.)

import threading	
import time

shared_number = 0	

def thread_1(number):
    global shared_number	
    print("number = ",end=""), print(number)
    
    for i in range(number):
        shared_number += 1

def thread_2(number):
    global shared_number	
    print("number = ",end=""), print(number)
    for i in range(number):
        shared_number += 1

if __name__ == "__main__":	

    threads = [ ]

    start_time = time.time()	
    
    t1 = threading.Thread( target= thread_1, args=(50000000,) )	
    t1.start()
    threads.append(t1)

    t2 = threading.Thread( target= thread_2, args=(50000000,) )
    t2.start()
    threads.append(t2)


    for t in threads:
        t.join()

    print("--- %s seconds ---" % (time.time() - start_time))

    print("shared_number=",end=""), print(shared_number)
    print("end of main")
  • thread๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” threading ๋ชจ๋“ˆ์„ importํ•ด์•ผํ•œ๋‹ค.
  • if __name__ == "__main__": ๋ฉ”์ธ ํŒŒ์ผ์ด ์ง์ ‘ ์‹คํ–‰ ๋˜์—ˆ์„ ๋•Œ ์‹คํ–‰ํ•  ์ฝ”๋“œ๋ฅผ ์ ์€ ๊ตฌ์—ญ์ด๋‹ค.
  • threading ํด๋ž˜์Šค์˜ Thread ๋ฉ”์†Œ๋“œ๋ฅผ ์ด์šฉํ•ด์„œ ๊ฐ์ฒด๋ฅผ ๋ฐ›์•„์˜จ๋‹ค. ์ด ๋•Œ ์ธ์ž๋กœ ์ฃผ๋Š” ๊ฒƒ์€ target์ด ๊ฐ€๋ฅดํ‚ค๋Š” ๊ฒƒ์€ thread๊ฐ€ ์‹คํ–‰์‹œํ‚ฌ ํ•จ์ˆ˜๋ฅผ ๋œปํ•˜๊ณ  args๋Š” ํ•จ์ˆ˜์— ์ „๋‹ฌํ•  ์ธ์ž๋กœ ๊ธฐ๋ณธ๊ฐ’์€ ()์ด๋‹ค. ์ถ”๊ฐ€์ ์ธ ์ธ์ž๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.
threading.Thread(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)
  • group๋Š” None๊ฐ’์ด ๋˜์•ผ๋งŒ ํ•œ๋‹ค. ํ›„์— ThreadGroup ํด๋ž˜์Šค๊ฐ€ ๊ฐœ์„ ๋  ๋•Œ๋ฅผ ์œ„ํ•ด ์˜ˆ์•ฝ๋œ ๊ฒƒ์ด๋‹ค.
  • name์€ thread์˜ ์ด๋ฆ„์ด๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ ๊ณ ์œ  ์ด๋ฆ„์€ โ€œThread-(10์ง„๋ฒ•์ˆ˜)โ€
  • .start()๋ฅผ ์ด์šฉํ•ด thread๋ฅผ ์‹คํ–‰์‹œํ‚จ๋‹ค.
  • .join()์€ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋๋‚  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ ค์ค€๋‹ค.

2๋ฒˆ

shared_number ๊ฐ€ ์ฒœ๋งŒ์œผ๋กœ ์ฆ๊ฐ€๋˜์ง€ ์•Š๋Š” ์ด์œ ๋ฅผ ์„ค๋ช…ํ•˜๊ณ ( ๋ธ”๋กœ๊ทธ ๋˜๋Š” ๋ฉ˜ํ† ์—๊ฒŒ ์„ค๋ช…)

  • shared_number๊ฐ€ ์ฒœ๋งŒ์œผ๋กœ ์ฆ๊ฐ€๋˜์ง€ ์•Š์€ ์ด์œ ๋Š” python์˜ GIL(Global Interpreter Lock) ๋•Œ๋ฌธ์ด๋‹ค. ํŒŒ์ด์ฌ์—์„œ๋Š” ํ•˜๋‚˜์˜ ํ”„๋กœ์„ธ์Šค ์•ˆ์— ๋ชจ๋“  ์ž์›์˜ ๋ฝ(Lock)์„ ๊ธ€๋กœ๋ฒŒ(Global)ํ•˜๊ฒŒ ๊ด€๋ฆฌํ•จ์œผ๋กœ์จ ํ•œ๋ฒˆ์— ํ•˜๋‚˜์˜ ์“ฐ๋ ˆ๋“œ๋งŒ ์ž์›์„ ์ปจํŠธ๋กคํ•˜์—ฌ ๋™์ž‘ํ•˜๋„๋ก ํ•œ๋‹ค. (thread์˜ ์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€ ์ฐธ๊ณ .) ์ฒœ๋งŒ๊นŒ์ง€ ์ฆ๊ฐ€ํ•˜๊ณ  ์žˆ์ง€ ์•Š์€ ๊ฒƒ์€ ํ•˜๋‚˜์˜ thread์—์„œ shared_number๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์œผ๋ฉด ๋‹ค๋ฅธ thread๋Š” ๊ทธ๊ฒƒ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๊ฒŒ ๋œ๋‹ค. ๊ทธ๋ ‡๊ธฐ์— ์ฒœ๋งŒ๊นŒ์ง€ ์ฆ๊ฐ€ํ•˜์ง€ ์•Š๊ฒŒ ๋œ ๊ฒƒ์ด๋‹ค. ์‹œ๊ฐ„์ด ์ ˆ๋ฐ˜๊นŒ์ง€ ์ค„์–ด๋“ค์ง€ ์•Š์€ ์ด์œ ๋„ ๊ฒฐ๊ตญ ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์˜ thread๋งŒ์ด ์ž์›์„ ์ปจํŠธ๋กคํ•จ์— ์žˆ์–ด์„œ ์‹œ๊ฐ„์ด ์ค„์–ด๋“ค์ง€ ์•Š์€ ๊ฒƒ์ด๋‹ค.

3๋ฒˆ

์œ„์˜ ์ฝ”๋“œ ๊ธฐ๋ฐ˜์œผ๋กœ ๋‘๊ฐœ์˜ ์“ฐ๋ ˆ๋“œ์—์„œ ๊ฐ๊ฐ 50000000์”ฉ ์ฆ๊ฐ€์‹œ์ผœ์„œ shared_number ๋ฅผ ์ฒœ๋งŒ์œผ๋กœ ์ฆ๊ฐ€์‹œํ‚ค๋Š” ์ฝ”๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ณผ์ œ ์ž…๋‹ˆ๋‹ค.( hint. ์กฐ๊ฑด๋ณ€์ˆ˜, ๋ฎคํ…์Šค )

๋ฎคํ…์Šค

import threading
import time

shared_number = 0

def thread_1(number,cv):
    global shared_number
    print("number = ",end=""), print(number)
    cv.acquire()	# Lock์„ ํš๋“ํ•˜๊ฒŒ ๋˜๊ณ  ๋‹ค๋ฅธ ๊ฐ์ฒด๊ฐ€ ์ ‘๊ทผํ•  ์ˆ˜ ์—†๋„๋ก ์ž ๊ทผ๋‹ค.
    for i in range(number):
        shared_number += 1
    cv.release()	# Lock์„ ํ’€์–ด์ค€๋‹ค. ๋‹ค๋ฅธ ๊ฐ์ฒด๊ฐ€ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.

def thread_2(number,cv):
    global shared_number
    print("number = ",end=""), print(number)
    cv.acquire()	# Lock์„ ํš๋“ํ•˜๊ฒŒ ๋˜๊ณ  ๋‹ค๋ฅธ ๊ฐ์ฒด๊ฐ€ ์ ‘๊ทผํ•  ์ˆ˜ ์—†๋„๋ก ์ž ๊ทผ๋‹ค.
    for i in range(number):
            shared_number += 1
    cv.release()	# Lock์„ ํ’€์–ด์ค€๋‹ค. ๋‹ค๋ฅธ ๊ฐ์ฒด๊ฐ€ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.

if __name__ == "__main__":

    threads = [ ]
    start_time = time.time()
    tc = threading.Lock()	#Lock ๊ฐ์ฒด ์ƒ์„ฑ
    t1 = threading.Thread( target= thread_1, args=(50000000,tc,) )
    t1.start()
    threads.append(t1)

    t2 = threading.Thread( target= thread_2, args=(50000000,tc,) )
    t2.start()
    threads.append(t2)


    for t in threads:
        t.join()	# thread๊ฐ€ ๋๋‚  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ ค์ค€๋‹ค.

    print("--- %s seconds ---" % (time.time() - start_time))
    print("shared_number=",end=""), print(shared_number)
    print("end of main")

  • tc = threading.Lock(): Lock ๊ฐ์ฒด ์ƒ์„ฑ
  • ์ƒ์„ฑํ•œ tc๋ฅผ thread ์ƒ์„ฑ ์‹œ์— ์‹คํ–‰ํ•  ํ•จ์ˆ˜์˜ ์ธ์ž๋กœ ์ „๋‹ฌ.
  • thread๊ฐ€ startํ•˜๋ฉด for๋ฌธ์„ ๋Œ๋ฉด์„œ lock์„ ์ž ๊ฐ”๋‹ค๊ฐ€ ํ’€์—ˆ๋‹ค๋ฅผ ๋ฐ˜๋ณตํ•˜๋ฉด์„œ ๊ฒฐ๊ตญ 1์–ต๊นŒ์ง€ ์ฐํžˆ๊ฒŒ ๋œ๋‹ค. ์„ธ๋งˆํฌ์–ด์™€์˜ ์ฐจ์ด์ ์€ ๋ฎคํ…์Šค๋Š” ๋ฌด์กฐ๊ฑด ํ•˜๋‚˜์˜ ์“ฐ๋ ˆ๋“œ ํ˜น์€ ํ”„๋กœ์„ธ์Šค๋งŒ ์ ‘๊ทผํ•˜๊ฒŒ ํ•œ๋‹ค๋Š” ์ ์ด๊ณ  ์„ธ๋งˆํฌ์–ด๋Š” ์ ‘๊ทผ ๊ฐ€๋Šฅ ๊ฐ์ฒด ์ˆ˜๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์ด๋‹ค.

์กฐ๊ฑด ๋ณ€์ˆ˜ ๊ฐ์ฒด

import threading
import time

shared_number = 0

def thread_1(number, cv, que):
    global shared_number

    for _ in range(number):
        cv.acquire()
        while len(que) < 1: 
            cv.wait()       
        que.pop()
        shared_number += 1

def thread_2(number, cv, que):
    global shared_number

    for _ in range(number):
        cv.acquire()
        que.append(shared_number)
        shared_number += 1
        cv.notify()
        cv.release()

if __name__ == "__main__":
    threads = [ ]
    que = []
    start_time = time.time()
    tc = threading.Condition()
    t1 = threading.Thread( target= thread_1, args=(50000000,tc,que) )
    t1.start()
    threads.append(t1)

    t2 = threading.Thread( target= thread_2, args=(50000000,tc,que) )
    t2.start()
    threads.append(t2)

    for t in threads:
        t.join()

    print("--- %s seconds ---" % (time.time() - start_time))
    print("shared_number=",end=""), print(shared_number)
    print("end of main")
  • tc = threading.Condition(): condition ๊ฐ์ฒด ์ƒ์„ฑ
  • condition ๊ฐ์ฒด๊ฐ€ ์ด์šฉ๋  ๊ณณ์— with๋ฌธ์œผ๋กœ ์ž‘์„ฑ.
  • ์ด์ „์˜ ๋ฎคํ…์Šค์™€์˜ ์ฐจ์ด์ ์œผ๋กœ๋Š” ๋จผ์ € wait()๊ณผ notify() ๋ฉ”์†Œ๋“œ๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. wait()์€ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ๊ฐœ์ฒด๊ฐ€ ์ƒ๊ธธ ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ๊ฒŒ ํ•˜๋Š” ๋ฉ”์†Œ๋“œ๊ณ  notify()๋Š” ๊ทธ๋ ‡๊ฒŒ wait()ํ•˜๊ณ  ์žˆ๋Š” ๊ฐ์ฒด๊ฐ€ ์žˆ๋‹ค๋ฉด ๊นจ์šฐ๋Š” ๋ฉ”์†Œ๋“œ์ด๋‹ค. ์ด ๋•Œ acquire()๋ฅผ ํ†ตํ•ด Lock๋ฅผ ๋จผ์ € ๊ฐ€์ง€๊ณ  ์žˆ์–ด์•ผ ํ•œ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด RuntimeError๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.
  • wait()์€ release()์˜ ์—ญํ•  ๋˜ํ•œ ๊ฐ€๋Šฅํ•˜๋‹ค.
  • que List๋Š” ๊ฒฐ๊ตญ while๋ฌธ ์•ˆ์—์„œ ๊ณ„์† wait()ํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ์„ ๋น ์ ธ๋‚˜์˜ฌ ์กฐ๊ฑด์„ ๋งŒ๋“ค๊ธฐ ์œ„ํ•œ ์žฅ์น˜์ด๋‹ค.
  • ์ƒ์„ฑํ•œ tc๋ฅผ thread ์ƒ์„ฑ ์‹œ์— ์‹คํ–‰ํ•  ํ•จ์ˆ˜์˜ ์ธ์ž๋กœ ์ „๋‹ฌ.

process๐Ÿง

1๋ฒˆ

์•„๋ž˜ ์ฐธ๊ณ ์ž๋ฃŒ์ธ ํŒŒ์ด์ฌ ๊ณต์‹๋ฌธ์„œ์—์„œ ํ•™์Šตํ•œ ๋‚ด์šฉ์— ๋Œ€ํ•ด์„œ ์ž์œ ๋กญ๊ฒŒ ๋ธ”๋กœ๊น…( ์‹คํ–‰ํ•ด๋ณธ ์˜ˆ์ œ์ฝ”๋“œ๋ฅผ ๋ถ„์„ํ•œ ๋‚ด์šฉ์„ ๋ธ”๋กœ๊น…ํ•ด๋„ ์ข‹๊ณ  ์ด๋ก ์ ์ธ ๋‚ด์šฉ์„ ๋ธ”๋กœ๊น…ํ•ด๋„ ์ข‹์Šต๋‹ˆ๋‹ค.)

from multiprocessing import Process, Queue
import time

def worker(id, number, q):
    increased_number = 0
    
    for i in range(number):
        increased_number += 1
    
    q.put(increased_number)	# put()์„ ํ†ตํ•ด Queue ๊ฐ์ฒด์— ๊ฐ’์„ ๋„ฃ๋Š”๋‹ค.

    return


if __name__ == "__main__":

    start_time = time.time()
    q = Queue()	# Queue

    th1 = Process(target=worker, args=(1, 50000000, q))
    th2 = Process(target=worker, args=(2, 50000000, q))

    th1.start()
    th2.start()
    th1.join()
    th2.join()


    print("--- %s seconds ---" % (time.time() - start_time))
    q.put('exit')

    total = 0
    while True:
        tmp = q.get()
        if tmp == 'exit':
            break
        else:
            total += tmp

    print("total_number=",end=""), print(total)
    print("end of main")

Process

threading์„ ์‚ฌ์šฉํ•  ๋•Œ์™€ ๊ฑฐ์˜ ๋™์ผํ•˜๋‹ค.

Pool()

Pool ํด๋ž˜์Šค๋Š” ์ž‘์—…์ž ํ”„๋กœ์„ธ์Šค ํ’€์„ ๋‚˜ํƒ€๋‚ธ๋‹ค.

from multiprocessing import Pool

def f(x):
	return x*x
    
if __name__ = '__main__':
	with Pool(processes = 4) as pool:
    
    	print(pool.map(f,range(10)))

์œ„์˜ ์ฝ”๋“œ๋Š” ๋‹ค์Œ ์ฝ”๋“œ์™€ ๊ฐ™์€ ์ฝ”๋“œ์ด๋‹ค.

def f(x):
	return x*x
    
if __name__ = '__main__':
	pool = Pool(processes = 4)
    print(pool.map(f,range(10)))
  • pool์„ ์ด์šฉํ•ด 4๊ฐœ์˜ ํ”„๋กœ์„ธ์Šค๊ฐ€ ๋ณ‘๋ ฌ์ฒ˜๋ฆฌ๋กœ ๋Œ์•„๊ฐ€๋„๋ก ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์œ„์˜ ์ฝ”๋“œ์—์„œ๋Š” ๊ฐ™์€ ์ž‘์—…์„ 4๋ฒˆ์„ ๋™์‹œ์— ๋Œ์•„๊ฐ€๊ฒŒ ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์ˆซ์ž๊ฐ€ ์ž‘์„ ๋•Œ๋Š” ์†๋„์— ๋ณ„ ์ฐจ์ด๊ฐ€ ์—†์„ ์ˆ˜ ์žˆ์œผ๋‚˜ ๋ฐ์ดํ„ฐ ์–‘์ด ๋ฐฉ๋Œ€ํ•ด์ง€๋ฉด ๊ทธ ์ฐจ์ด๋Š” ์–ด๋งˆ์–ด๋งˆํ•˜๋‹ค๊ณ  ํ•œ๋‹ค.

ํ”„๋กœ์„ธ์Šค ์‚ฌ์ด์— ์˜์‚ฌ์†Œํ†ตํ•  ์ˆ˜ ์žˆ๋Š” ๋‘ ๊ฐ€์ง€ ํƒ€์ž…์ด ์กด์žฌํ•œ๋‹ค. Queue์™€ Pipe๊ฐ€ ํ•ด๋‹น๋œ๋‹ค.

Queue()

Queue๋Š” q.put()์„ ํ†ตํ•ด ๊ฐ’์„ ๋„ฃ๊ณ  q.get()์„ ํ†ตํ•ด ๊ฐ’์„ ์–ป๋Š”๋‹ค. ์œ„์˜ ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด๋ฉด q์— ๊ฐ๊ฐ์˜ ์ฆ๊ฐ€๋œ ์ˆซ์ž๋ฅผ ์ž…๋ ฅํ•˜๊ณ  ๋งˆ์ง€๋ง‰ ๋ถ€๋ถ„์˜ while๋ฌธ์„ ํ†ตํ•ด tmp์— ๊ฐ’์„ ๋‹ด๊ณ  total์— ๋”ํ•ด์„œ, ์ฆ‰ ๊ฐ๊ฐ 50000000์˜ ์ˆซ์ž๋ฅผ ๋”ํ•ด 100000000์ด๋ผ๋Š” total๊ฐ‘์„ ์–ป๊ฒŒ ๋œ๋‹ค.

Pipe()

Pipe๋Š” ํ•œ ์Œ์˜ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š”๋ฐ ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ๋จผ์ € ์‚ดํŽด๋ณด์ž.

from multiprocessing import Process, Pipe

def f(conn):
    conn.send([42, None, 'hello'])
    conn.close()

if __name__ == '__main__':
    parent_conn, child_conn = Pipe()
    p = Process(target=f, args=(child_conn,))
    p.start()
    print(parent_conn.recv())   # prints "[42, None, 'hello']"
    p.join()

parent_conn๊ณผ child_conn์ด ํ•œ ์Œ์˜ ์—ฐ๊ฒฐ๋œ ๊ฐ์ฒด์ด๋‹ค. ์ฆ‰ child_conn์—์„œ send()๋ฅผ ํ†ตํ•ด ๊ฐ’์„ ์ž…๋ ฅํ•˜๊ณ  parent_conn์„ ํ†ตํ•ด ๊ฐ’์„ ์–ป๋Š”๋‹ค. ์ฆ‰ ๊ฐ๊ฐ ์—ฐ๊ฒฐ๋œ ๊ฐ์ฒด์ด๋‹ค. ํ•˜์ง€๋งŒ ๊ฐ™์€ ์ชฝ์—์„œ ์ฝ๊ณ  ์“ฐ๋Š” ์ž‘์—…์„ ๋™์‹œ์— ์ง„ํ–‰ํ•˜๋ ค๊ณ  ํ•œ๋‹ค๋ฉด ๋ฐ์ดํ„ฐ์˜ ์†์ƒ์„ ๋ฐœ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.

2๋ฒˆ

์œ„์˜ ์ฝ”๋“œ ๊ธฐ๋ฐ˜์œผ๋กœ ์•„๋ž˜ ํŒŒ์ด์ฌ ๊ณต์‹ ๋ฌธ์„œ๋ฅผ ํ•™์Šตํ•œํ›„, IPC๋ฐฉ์‹์ค‘ ๊ณต์œ  ๋ฉ”๋ชจ๋ฆฌ ๋ฐฉ์‹์œผ๋กœ ๋‘๊ฐœ์˜ ํ”„๋กœ์„ธ์Šค๋กœ 50000000์”ฉ ์ฆ๊ฐ€์‹œํ‚ค๊ณ  ๊ณต์œ  ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์„ธ๋งˆํฌ์–ด๋กœ ๋™๊ธฐํ™” ์‹œ์ผœ ์ตœ์ข… ๊ฐ’์œผ๋กœ 1์–ต์„ ๋งŒ๋“œ๋Š” ์ฝ”๋“œ๋ฅผ ๊ตฌํ˜„ํ•ด ๋ณด์„ธ์š”.

from multiprocessing import Process, Semaphore, shared_memory
import time
import numpy as np

def worker(id, number, a, s, shm):
    increased_number = 0
    for i in range(number):
        increased_number += 1

    s.acquire()
    ex_shm = shared_memory.SharedMemory(name=shm)
    c = np.ndarray(a.shape, dtype=a.dtype, buffer=ex_shm.buf)
    c[0] += increased_number
    s.release()

    return

if __name__ == "__main__":

    start_time = time.time()
    a = np.array([0])
    shm = shared_memory.SharedMemory(create = True, size = a.nbytes)
    b = np.ndarray(a.shape, dtype=a.dtype, buffer=shm.buf)
    s = Semaphore()
    th1 = Process(target=worker, args=(0, 50000000, a, s, shm.name))
    th2 = Process(target=worker, args=(1, 50000000, a, s, shm.name))

    th1.start()
    th2.start()
    th1.join()
    th2.join()

    print("--- %s seconds ---" % (time.time() - start_time))
    print('exit')


    print("total_number=",end=""), print(b[0])
    print("end of main")
    
    shm.close()
    shm.unlink()
  • main ์•ˆ์—์„œ ๊ณต์œ  ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก์„ ์ƒ์„ฑํ•˜๊ณ  ๊ทธ ์•ˆ์— numpy๋ฐฐ์—ด์„ ์‚ฌ์ „์— ๋งŒ๋“ค์–ด์„œ ๊ฐ’์„ ๋„ฃ์–ด๋‘” a์™€ ๋™์ผํ•œ ํ˜•์‹์œผ๋กœ ์ƒ์„ฑํ•œ ํ›„ ๊ฐ๊ฐ์˜ ํ”„๋กœ์„ธ์Šค์˜ numpy ๋ฐฐ์—ด์˜ ํ™˜๊ฒฝ๊ณผ ๊ณต์œ  ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก์˜ ์ด๋ฆ„์„ ๋„˜๊ฒจ์ฃผ์–ด ์—ฐ๊ฒฐ๋œ ํ™˜๊ฒฝ์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.
  • ๊ทธ ์ด์œ ๋Š” ํ”„๋กœ์„ธ์Šค๋Š” ๊ฐ๊ธฐ ๋‹ค๋ฅธ ์ž‘์—… ๊ณต๊ฐ„์„ ๊ฐ€์ง€๊ณ  ์žˆ๊ธฐ์— ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น ๋˜ํ•œ ๊ฐ๊ฐ ๋‹ค๋ฅธ ์˜์—ญ์— ํ• ๋‹น๋œ๋‹ค. ๊ทธ๋ ‡๊ธฐ์— ๊ฐ๊ฐ์˜ ํ”„๋กœ์„ธ์Šค์— ํ•˜๋‚˜์˜ ๊ณต์œ  ๋ฉ”๋ชจ๋ฆฌ์™€ ์—ฐ๊ฒฐ๋  ์ˆ˜ ์žˆ๋„๋ก ๊ณต์œ  ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก์„ ์—ฐ๊ฒฐํ•˜๊ณ  ๊ทธ ์•ˆ์— ๊ฐ™์€ ํ˜•์‹์˜ ๋ฐฐ์—ด์„ ๋งŒ๋“ค์–ด ๊ทธ ๋ฐฐ์—ด์˜ ๊ฐ’์„ ํ†ตํ•ด ์—ฐ์‚ฐ์„ ํ•˜๊ณ  ๋™๊ธฐํ™”๊ฐ€ ์ด๋ฃจ์–ด์งˆ ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.
  • ์„ธ๋งˆํฌ์–ด๋Š” ๋ฎคํ…์Šค์™€ ์œ ์‚ฌํ•œ ๊ฐœ๋…์œผ๋กœ ์„ธ๋งˆํฌ์–ด ์ƒ์„ฑ ์‹œ ํ”„๋กœ์„ธ์Šค์˜ ์ ‘๊ทผ ๊ฐ€๋Šฅ ๊ฐฏ์ˆ˜๋ฅผ 1๋กœ ์„ค์ •ํ•˜๋ฉด ๋ฎคํ…์Šค์™€ ๋™์ผํ•˜๋‹ค. 2๋กœ ์„ค์ •ํ•˜๋ฉด 2๊ฐœ์˜ ํ”„๋กœ์„ธ์Šค๊ฐ€ ๊ฐ™์€ ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผ ๊ฐ€๋Šฅํ•˜๋‹ค. ์ฆ‰ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ๊ฐœ์ˆ˜๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ndarray๋Š” ๊ธฐ์กด ํŒŒ์ด์ฌ๊ณผ๋Š” ๋‹ค๋ฅด๊ฒŒ ์˜ค์ง ๊ฐ™์€ ์ข…๋ฅ˜์˜ ๋ฐ์ดํ„ฐ๋งŒ์„ ๋ฆฌ์ŠคํŠธ์— ๋‹ด์„ ์ˆ˜ ์žˆ๋‹ค.

shared_memory

์ด ๋ชจ๋“ˆ์€ ๋ฉ€ํ‹ฐ ์ฝ”์–ด๋‚˜ ๋Œ€์นญ ๋ฉ€ํ‹ฐ ํ”„๋กœ์„ธ์„œ (SMP) ๊ธฐ๊ณ„์—์„œ ํ•˜๋‚˜ ์ด์ƒ์˜ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ ‘๊ทผํ•  ๊ณต์œ  ๋ฉ”๋ชจ๋ฆฌ์˜ ํ• ๋‹น๊ณผ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•œ ํด๋ž˜์Šค SharedMemory๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

class multiprocessing.shared_memory.SharedMemory(name=None, create=False, size=0)
  • name์ด None์œผ๋กœ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋ฉด ์ƒˆ๋กœ์šด ๊ณต์œ  ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก์„ ์ƒ์„ฑํ•œ๋‹ค. ํ•˜์ง€๋งŒ name์— ๊ธฐ์กด์— ์ƒ์„ฑ๋˜์–ด ์žˆ๋Š” ๊ณต์œ  ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก์˜ ์ด๋ฆ„์„ ๋„ฃ์œผ๋ฉด ๊ธฐ์กด์˜ ๊ณต์œ  ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก๊ณผ ์—ฐ๊ฒฐ๋œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ฒŒ ๋œ๋‹ค.
  • create๋Š” True์ผ ๊ฒฝ์šฐ ์ƒˆ๋กœ์šด ๊ณต์œ  ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก์„ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด๊ณ  False์ผ ๊ฒฝ์šฐ ๊ธฐ์กด ๊ณต์œ  ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก์„ ์—ฐ๊ฒฐํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.
  • size๋Š” ์ƒˆ ๊ณต์œ  ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก์„ ๋งŒ๋“ค ๋•Œ ์š”์ฒญ๋œ ๋ฐ”์ดํŠธ ์ˆ˜๋ฅผ ์ง€์ •ํ•œ๋‹ค. ๊ธฐ๋ณธ ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก๊ณผ ์—ฐ๊ฒฐํ•  ๋•Œ๋Š” size ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ๋ฌด์‹œ๋œ๋‹ค.
  • close()๋ฅผ ํ†ตํ•ด ๊ณต์œ  ๋ฉ”๋ชจ๋ฆฌ์— ๋Œ€ํ•œ ์•ก์„ธ์Šค๋ฅผ ๋‹ซ์•„์•ผ ํ•œ๋‹ค. ์ž์›์„ ์ ์ ˆํžˆ ์ •๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด์„œ ๋”๋Š” ํ•„์š”ํ•˜์ง€ ์•Š์œผ๋ฉด ๋ชจ๋“  ์ธ์Šคํ„ด์Šค๊ฐ€ close()๋ฅผ ํ•ด์•ผํ•œ๋‹ค.
  • unlink()๋Š” ๋ชจ๋“  ํ”„๋กœ์„ธ์Šค ์ „์ฒด์—์„œ ๋‹จ ํ•œ ๋ฒˆ๋งŒ ํ˜ธ์ถœํ•ด์•ผํ•œ๋‹ค. unlink()๊ฐ€ ํ˜ธ์ถœ๋œ ํ›„์—๋Š” ๊ณต์œ  ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก์ด ์ฆ‰์‹œ ํŒŒ๊ดด๋œ๋‹ค. ๋งˆ์ง€๋ง‰ ํ”„๋กœ์„ธ์Šค๋Š” unlink()์™€ close()๋ฅผ ์–ด๋А ์ˆœ์„œ๋กœ๋“  ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค.
  • buf: ๊ณต์œ  ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก์˜ ๋‚ด์šฉ์— ๋Œ€ํ•œ ๋ฉ”๋ชจ๋ฆฌ ๋ทฐ
  • name: ๊ณต์œ  ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก์˜ ๊ณ ์œ ํ•œ ์ด๋ฆ„์— ๋Œ€ํ•œ ์ฝ๊ธฐ ์ „์šฉ ์•ก์„ธ์Šค
  • size: ๊ณต์œ  ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก์˜ ํฌ๊ธฐ(๋ฐ”์ดํŠธ)์— ๋Œ€ํ•œ ์ฝ๊ธฐ ์ „์šฉ ์•ก์„ธ์Šค

NumPy๋ž€?

Numerical Python์˜ ์ค„์ž„ ๋ง๋กœ์จ ๊ณ ์„ฑ๋Šฅ์˜ ์ˆ˜์น˜ ๊ณ„์‚ฐ์„ ํ•˜๊ธฐ ์œ„ํ•ด ๋งŒ๋“ค์–ด์ง„ C์–ธ์–ด๋กœ ๊ตฌํ˜„๋œ python package์ด๋‹ค. ํŒŒ์ด์ฌ์„ ์ด์šฉํ•œ ๋ฐ์ดํ„ฐ ๋ถ„์„์„ ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” pandas ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ numpy๋ฅผ ์ตํ˜€์•ผ๋งŒ ๋ณด๋‹ค ํ˜ธ์œจ์ ์ธ ๋ฐ์ดํ„ฐ ๋ถ„์„์ด ๊ฐ€๋Šฅํ•˜๋‹ค. ndarray๋Š” ์„ฑ๋Šฅํ–ฅ์ƒ์„ ์œ„ํ•ด ๊ฐ™์€ ๋ฐ์ดํ„ฐํƒ€์ž…๋งŒ์„ ์š”์†Œ๋กœ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๊ณ , ํฌ๊ธฐ ์—ญ์‹œ ๊ณ ์ •๋˜์–ด ์žˆ๋‹ค. ๋งŒ์•ฝ ํฌ๊ธฐ๋ฅผ ๋ณ€๊ฒฝํ•˜๋ฉด ์ƒˆ๋กœ ๋ฉ”๋ชจ๋ฆฌ์— ํ• ๋‹น๋˜๊ณ  ์ด์ „ ๊ฐ’์€ ์‚ญ์ œ๋œ๋‹ค.

  • numpy shape(arr.shape): numpy์—์„œ๋Š” ํ•ด๋‹น array์˜ ํฌ๊ธฐ๋ฅผ ์•Œ ์ˆ˜ ์žˆ๋‹ค. shape ์„ ํ™•์ธํ•จ์œผ๋กœ์จ ๋ช‡๊ฐœ์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๋Š”์ง€, ๋ช‡ ์ฐจ์›์œผ๋กœ ์กด์žฌํ•˜๋Š”์ง€ ๋“ฑ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

  • numpy ์ž๋ฃŒํ˜•(arr.dtype)
    ๋ถ€ํ˜ธ๊ฐ€ ์žˆ๋Š” ์ •์ˆ˜ int(8, 16, 32, 64)
    ๋ถ€ํ˜ธ๊ฐ€ ์—†๋Š” ์ •์ˆ˜ uint(8 ,16, 32, 54)
    ์‹ค์ˆ˜ float(16, 32, 64, 128)
    ๋ณต์†Œ์ˆ˜ complex(64, 128, 256)
    ๋ถˆ๋ฆฌ์–ธ bool
    ๋ฌธ์ž์—ด string
    ํŒŒ์ด์ฌ ์˜คํ”„์ ํŠธ object
    ์œ ๋‹ˆ์ฝ”๋“œ unicode

coroutine๐Ÿง

1๋ฒˆ

  1. ์ฒซ๋ฒˆ์งธ ์˜ˆ์ œ ์ฝ”๋“œ๋Š” greeting์— ๋ฌธ์ž์—ด์ด send ๋ณด๋‚ผ๋•Œ ๋งˆ๋‹ค ๊ณ„์† ๋”ํ•ด์ง€๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ๊ณผ ๊ฐ™์ด send ํ˜ธ์ถœ์‹œ๋งˆ๋‹ค good morning, good afternoon, good evening ์ด ์ถœ๋ ฅ๋˜๋„๋ก ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•ด๋ณด์„ธ์š”
print(cr.send("morning")) โ†’ good morning
print(cr.send("afternoon")) โ†’ good afternoon
print(cr.send("evening")) โ†’ good evening
import time

def coroutine_test():
    greeting = "good "
    while True:
        text = (yield greeting)
        print("text = ",end=""), print(text)
        greeting = "good "	# ์ด ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•จ
        greeting += text


if __name__ == "__main__":
    cr = coroutine_test()
    print("cr=",end=""), print(cr)

    next(cr)
    time.sleep(2)

    print("send 1")
    print(cr.send("morning"))
    time.sleep(2)

    print("send 2")
    print(cr.send("afternoon"))
    time.sleep(2)

    print("send 3")
    print(cr.send("evening"))
    time.sleep(2)
  • ์ˆ˜์ • ์ „ ํ›„์˜ ์ถœ๋ ฅ ํ™”๋ฉด

2๋ฒˆ

asyncio ์— ๋Œ€ํ•ด์„œ ํ•™์Šตํ•œ ํ›„ ๋‘๋ฒˆ์งธ ์ฝ”๋“œ๋ฅผ coroutine ๊ณผ asyncio ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๊ตฌํ˜„ํ•ด ๋ณด์„ธ์š”.

import time
import asyncio

async def coroutine_test(num, a):
    greeting = "good "
    await asyncio.sleep(2)
    print(f"send {num}")
    print("text = ",end=""), print(a)
    greeting += a
    print(greeting)

if __name__ == "__main__":
    L = ["morning","afternoon","evening"]
    loop = asyncio.get_event_loop()
    loop.run_until_complete(coroutine_test(1, L[0]))
    loop.run_until_complete(coroutine_test(2, L[1]))
    loop.run_until_complete(coroutine_test(3, L[2]))
    loop.close()
  • ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ๊ธฐ๋ฐ˜์˜ ์ฝ”๋ฃจํ‹ด๊ณผ asyncio ๊ธฐ๋ฐ˜์˜ ์ฝ”๋ฃจํ‹ด ์ถœ๋ ฅ ๊ฒฐ๊ณผ

3๋ฒˆ

์ œ๋„ˆ๋ ˆ์ดํ„ฐ ๊ธฐ๋ฐ˜์˜ ์ฝ”๋ฃจํ‹ด

์ œ๋„ˆ๋ ˆ์ดํ„ฐ ๊ธฐ๋ฐ˜ ์ฝ”๋ฃจํ‹ด์— ๋Œ€ํ•œ ์ง€์›์€ ํ์ง€๋˜์—ˆ๊ณ  ํŒŒ์ด์ฌ 3.10์—์„œ ์‚ญ์ œ๋  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค.(๊ณต์‹ ๋ฌธ์„œ)

์ฝ”๋ฃจํ‹ด์€ ํ•จ์ˆ˜๊ฐ€ ์ข…๋ฃŒ๋˜์ง€ ์•Š์€ ์ƒํƒœ์—์„œ ๋ฉ”์ธ ๋ฃจํ‹ด์˜ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•œ ๋’ค ๋‹ค์‹œ ๋Œ์•„์™€์„œ ์ฝ”๋ฃจํ‹ด์˜ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ฝ”๋ฃจํ‹ด์ด ์ข…๋ฃŒ๋˜์ง€ ์•Š์•˜์œผ๋ฏ€๋กœ ์ฝ”๋ฃจํ‹ด์˜ ๋‚ด์šฉ๋„ ๊ณ„์† ์œ ์ง€๋ฉ๋‹ˆ๋‹ค.

1๋ฒˆ์— ํ•ด๋‹นํ•˜๋Š” ์ฝ”๋“œ๋กœ ์ƒ๊ฐํ•˜๋Š” ๊ฒƒ์ด ํŽธํ•˜๋‹ค. while๋ฌธ ์†์—์„œ ๋ฌดํ•œํžˆ ๋ฐ˜๋ณตํ•˜๋ฉด์„œ yield๋ถ€๋ถ„์—์„œ ๊ฐ’์ด ๋“ค์–ด์˜ค๊ธฐ๋ฅผ ๋Œ€๊ธฐํ•˜๊ณ  ์žˆ๋Š” ์ƒํ™ฉ์ด๋‹ค.

1๋ฒˆ ์ฝ”๋“œ์—์„œ next(cr) ๋ถ€๋ถ„์ด ๊ทธ๋ฆผ์˜ ์ตœ์ดˆ ํ˜ธ์ถœ์— ํ•ด๋‹นํ•˜๊ณ  yield์— ๋„๋‹ฌํ–ˆ์„ ๋•Œ ๊ฐ’์ด ๋“ค์–ด์˜ค๊ธธ ๊ธฐ๋‹ค๋ ธ๋‹ค๊ฐ€ ๋ฉ”์ธ ๋ฃจํ‹ด์—์„œ send๋ฅผ ํ†ตํ•ด ๊ฐ’์„ ์ „๋‹ฌ๋ฐ›์œผ๋ฉด ๋‹ค์Œ ์ฝ”๋“œ๋ฅผ ์ง„ํ–‰ํ•˜๊ณ  ๋‹ค์‹œ yield๋ฅผ ํ†ตํ•ด ๊ฐ’์„ ๋‚ด๋ณด๋‚ด๋ฉด์„œ ๋‹ค์‹œ ๋Œ€๊ธฐ ์ƒํƒœ๋กœ ๋“ค์–ด๊ฐ„๋‹ค.

close()๋ฅผ ํ†ตํ•ด ์ฝ”๋ฃจํ‹ด์„ ์ข…๋ฃŒํ•  ์ˆ˜ ์žˆ๊ณ  throw๋กœ ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œ์ผœ ์ข…๋ฃŒ์‹œํ‚ฌ ์ˆ˜๋„ ์žˆ๋‹ค.

yield from์— ์ฝ”๋ฃจํ‹ด๋ฅผ ์ง€์ •ํ•˜๋ฉด ํ•ด๋‹น ์ฝ”๋ฃจํ‹ด์—์„œ return์œผ๋กœ ๋ฐ˜ํ™˜ํ•œ ๊ฐ’์„ ๊ฐ€์ ธ์˜จ๋‹ค. ๋˜ํ•œ ์ฝ”๋ฃจํ‹ด์—์„œ yield from์„ ์‚ฌ์šฉํ•˜๋ฉด ์ฝ”๋ฃจํ‹ด ๋ฐ”๊นฅ์—์„œ send๋กœ ํ•˜์œ„ ์ฝ”๋ฃจํ‹ด๊นŒ์ง€ ๊ฐ’์„ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋‹ค. (์•„๋ž˜ ์ฝ”๋“œ ์ฐธ๊ณ )(์ถœ์ฒ˜:ํŒŒ์ด์ฌ ์ฝ”๋”ฉ ๋„์žฅ)

def accumulate():
    total = 0
    while True:
        x = (yield)         # ์ฝ”๋ฃจํ‹ด ๋ฐ”๊นฅ์—์„œ ๊ฐ’์„ ๋ฐ›์•„์˜ด
        if x is None:       # ๋ฐ›์•„์˜จ ๊ฐ’์ด None์ด๋ฉด
            return total    # ํ•ฉ๊ณ„ total์„ ๋ฐ˜ํ™˜
        total += x
 
def sum_coroutine():
    while True:
        total = yield from accumulate()    # accumulate์˜ ๋ฐ˜ํ™˜๊ฐ’์„ ๊ฐ€์ ธ์˜ด
        print(total)
 
co = sum_coroutine()
next(co)
 
for i in range(1, 11):    # 1๋ถ€ํ„ฐ 10๊นŒ์ง€ ๋ฐ˜๋ณต
    co.send(i)            # ์ฝ”๋ฃจํ‹ด accumulate์— ์ˆซ์ž๋ฅผ ๋ณด๋ƒ„
co.send(None)             # ์ฝ”๋ฃจํ‹ด accumulate์— None์„ ๋ณด๋‚ด์„œ ์ˆซ์ž ๋ˆ„์ ์„ ๋๋ƒ„
 
for i in range(1, 101):   # 1๋ถ€ํ„ฐ 100๊นŒ์ง€ ๋ฐ˜๋ณต
    co.send(i)            # ์ฝ”๋ฃจํ‹ด accumulate์— ์ˆซ์ž๋ฅผ ๋ณด๋ƒ„
co.send(None)             # ์ฝ”๋ฃจํ‹ด accumulate์— None์„ ๋ณด๋‚ด์„œ ์ˆซ์ž ๋ˆ„์ ์„ ๋๋ƒ„

asyncio ๊ธฐ๋ฐ˜์˜ ์ฝ”๋ฃจํ‹ด

async/await ๋ฌธ๋ฒ•์œผ๋กœ ์„ ์–ธ๋œ ์ฝ”๋ฃจํ‹ด์€ asyncio ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์„ ์ž‘์„ฑํ•˜๋Š” ๊ธฐ๋ณธ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. asyncio ๊ธฐ๋ฐ˜์œผ๋กœ ๋งŒ๋“ค์–ด์ง„ ์ฝ”๋ฃจํ‹ด์„ ๋„ค์ดํ‹ฐ๋ธŒ ์ฝ”๋ฃจํ‹ด์ด๋ผ๊ณ  ํ•œ๋‹ค.

๋จผ์ € asyncio๋Š” async/await ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋™์‹œ์„ฑ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค. asyncio๋Š” ๊ณ ์„ฑ๋Šฅ ๋„คํŠธ์›Œํฌ ๋ฐ ์›น ์„œ๋ฒ„, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ, ๋ถ„์‚ฐ ์ž‘์—… ํ ๋“ฑ์„ ์ œ๊ณตํ•˜๋Š” ์—ฌ๋Ÿฌ ํŒŒ์ด์ฌ ๋น„๋™๊ธฐ ํ”„๋ ˆ์ž„์›Œํฌ์˜ ๊ธฐ๋ฐ˜์œผ๋กœ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. asyncio๋Š” ์ข…์ข… IO ๋ณ‘๋ชฉ์ด๋ฉด์„œ ๊ณ ์ˆ˜์ค€์˜ ๊ตฌ์กฐํ™”๋œ ๋„คํŠธ์›Œํฌ ์ฝ”๋“œ์— ๊ฐ€์žฅ ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.

  • ๋™๊ธฐ ์ฒ˜๋ฆฌ vs ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ(์ถœ์ฒ˜: ์ฝ”๋”ฉ๋„์žฅ)

๋„ค์ดํ‹ฐ๋ธŒ ์ฝ”๋ฃจํ‹ด ๋งŒ๋“ค๊ธฐ

async def ํ•จ์ˆ˜์ด๋ฆ„():
	์ฝ”๋“œ

์–ด์›จ์ดํ„ฐ๋ธ”

await ํ‘œํ˜„์‹์—์„œ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ์„ ๋•Œ ์–ด์›จ์ดํ„ฐ๋ธ” ๊ฐ์ฒด๋ผ๊ณ  ๋งํ•ฉ๋‹ˆ๋‹ค. ์ฝ”๋ฃจํ‹ด, ํƒœ์Šคํฌ, ํ“จ์ฒ˜

์ฝ”๋ฃจํ‹ด

ํŒŒ์ด์ฌ ์ฝ”๋ฃจํ‹ด์€ ์–ด์›จ์ดํ„ฐ๋ธ”๋กœ ๋‹ค๋ฅธ ์ฝ”๋ฃจํ‹ด์—์„œ ๊ธฐ๋‹ค๋ฆด ์ˆ˜ ์žˆ๋‹ค.

import asyncio

async def nested():
    return 42

async def main():
    nested()	# ๊ทธ๋ƒฅ ํ˜ธ์ถœ๋งŒ ํ•œ ์ƒํƒœ๋กœ ์‹คํ–‰๋˜์ง€๋Š” ์•Š๋Š”๋‹ค.
    print(await nested())	# nested()๊ฐ€ ๋๋‚  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ ธ๋‹ค๊ฐ€ ๋๋‚˜๋ฉด 42๊ฐ€ ํ”„๋ฆฐํŠธ ๋  ์˜ˆ์ •
    
asyncio.run(main())	# ๋ฉ”์ธ์„ ์‹คํ–‰์‹œ์ผœ์„œ nested()๋ฅผ ์‹คํ–‰์‹œํ‚ค๊ณ  42๋ฅผ ํ”„๋ฆฐํŠธ ํ•จ
  • ์ฝ”๋ฃจํ‹ด ํ•จ์ˆ˜: async def ํ•จ์ˆ˜;
  • ์ฝ”๋ฃจํ‹ด ๊ฐ์ฒด: ์ฝ”๋ฃจํ‹ด ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋ฐ˜ํ™˜๋œ ๊ฐ์ฒด.

ํƒœ์Šคํฌ

ํƒœ์Šคํฌ๋Š” ์ฝ”๋ฃจํ‹ด์„ ๋™์‹œ์— ์˜ˆ์•ฝํ•˜๋Š”๋ฐ ์‚ฌ์šฉ๋œ๋‹ค. ์ฝ”๋ฃจํ‹ด์ด asyncio.create_task()์™€ ๊ฐ™์€ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํƒœ์Šคํฌ๋กœ ์‹ธ์ผ ๋•Œ ์ฝ”๋ฃจํ‹ด์€ ๊ณง ์‹คํ–‰๋˜๋„๋ก ์ž๋™์œผ๋กœ ์˜ˆ์•ฝ๋œ๋‹ค.

import asyncio

async def nested():
    return 42

async def main():
	# asyncio.create_task() ํƒœ์Šคํฌ ๋งŒ๋“ค๊ธฐ ํ•จ์ˆ˜
    task = asyncio.create_task(nested())	# ์˜ˆ์•ฝ
    await task	task๊ฐ€ ๋๋‚  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆผ

asyncio.run(main())
  • ํƒœ์Šคํฌ(asyncio.Task)๋Š” asyncio.Future์˜ ํŒŒ์ƒ ํด๋ž˜์Šค์ด๋ฉฐ asyncio.Future์˜ ๊ธฐ๋Šฅ๊ณผ ์‹คํ–‰ํ•  ์ฝ”๋ฃจํ‹ด์˜ ๊ฐ์ฒด๋ฅผ ํฌํ•จํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ํƒœ์Šคํฌ๋Š” ์ฝ”๋ฃจํ‹ด์˜ ์‹คํ–‰์„ ์ทจ์†Œํ•˜๊ฑฐ๋‚˜ ์ƒํƒœ ํ™•์ธ, ์™„๋ฃŒ ๋ฐ ๊ฒฐ๊ณผ ์„ค์ •์— ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

ํ“จ์ฒ˜

Future๋Š” ๋น„๋™๊ธฐ ์—ฐ์‚ฐ์˜ ์ตœ์ข… ๊ฒฐ๊ณผ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ํŠน๋ณ„ํ•œ ์ €์ˆ˜์ค€ ์–ด์›จ์ดํ„ฐ๋ธ” ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค. Future ๊ฐ์ฒด๋ฅผ ๊ธฐ๋‹ค๋ฆด ๋•Œ, ๊ทธ๊ฒƒ์€ ์ฝ”๋ฃจํ‹ด์ด Future๊ฐ€ ๋‹ค๋ฅธ ๊ณณ์—์„œ ํ•ด๊ฒฐ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆด ๊ฒƒ์„ ๋œปํ•ฉ๋‹ˆ๋‹ค. ์ฝœ๋ฐฑ ๊ธฐ๋ฐ˜ ์ฝ”๋“œ๋ฅผ async/await์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋ ค๋ฉด asyncio์˜ Future ๊ฐ์ฒด๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ ์ˆ˜์ค€ ์ฝ”๋“œ์—์„œ Future ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค. ๋•Œ๋•Œ๋กœ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ์ผ๋ถ€ asyncio API์— ์˜ํ•ด ๋…ธ์ถœ๋˜๋Š” Future ๊ฐ์ฒด๋ฅผ ๊ธฐ๋‹ค๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Future ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ €์ˆ˜์ค€ ํ•จ์ˆ˜์˜ ์˜ˆ๋Š” loop.run_in_executor()์ด๋‹ค.

async def main():
    await function_that_returns_a_future_object()

    # this is also valid:
    await asyncio.gather(
        function_that_returns_a_future_object(),
        some_python_coroutine()
    )
  • ํ“จ์ฒ˜(asyncio.Future)๋Š” ๋ฏธ๋ž˜์— ํ•  ์ผ์„ ํ‘œํ˜„ํ•˜๋Š” ํด๋ž˜์Šค์ธ๋ฐ ํ•  ์ผ์„ ์ทจ์†Œํ•˜๊ฑฐ๋‚˜ ์ƒํƒœ ํ™•์ธ, ์™„๋ฃŒ ๋ฐ ๊ฒฐ๊ณผ ์„ค์ •์— ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

asyncio ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ํ•˜๊ธฐ

asyncio.run(coro, *, debug=False)
  • ์ฝ”๋ฃจํ‹ด coro๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜๋Š” ์ „๋‹ฌ๋œ ์ฝ”๋ฃจํ‹ด์„ ์‹คํ–‰ํ•˜๊ณ , asyncio ์ด๋ฒคํŠธ ๋ฃจํ”„์™€ ๋น„๋™๊ธฐ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ์˜ ํŒŒ์ด๋„๋ฆฌ์ œ์ด์…˜์„ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ asyncio ์ด๋ฒคํŠธ ๋ฃจํ”„๊ฐ€ ๊ฐ™์€ ์Šค๋ ˆ๋“œ์—์„œ ์‹คํ–‰ ์ค‘์ผ ๋•Œ, ์ด ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
  • debug์ด True๋ฉด, ์ด๋ฒคํŠธ ๋ฃจํ”„๊ฐ€ ๋””๋ฒ„๊ทธ ๋ชจ๋“œ๋กœ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.
  • ์ด ํ•จ์ˆ˜๋Š” ํ•ญ์ƒ ์ƒˆ ์ด๋ฒคํŠธ ๋ฃจํ”„๋ฅผ ๋งŒ๋“ค๊ณ  ๋์— ์ด๋ฒคํŠธ ๋ฃจํ”„๋ฅผ ๋‹ซ์Šต๋‹ˆ๋‹ค. asyncio ํ”„๋กœ๊ทธ๋žจ์˜ ๋ฉ”์ธ ์ง„์ž… ์ง€์ ์œผ๋กœ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๊ณ , ์ด์ƒ์ ์œผ๋กœ๋Š” ํ•œ ๋ฒˆ๋งŒ ํ˜ธ์ถœํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

sleep

asyncio.sleep(delay, result=None, *, loop=None)
  • delay ์ดˆ ๋™์•ˆ ๋ธ”๋กํ•ฉ๋‹ˆ๋‹ค.
  • result๊ฐ€ ์ œ๊ณต๋˜๋ฉด, ์ฝ”๋ฃจํ‹ด์ด ์™„๋ฃŒ๋  ๋•Œ ํ˜ธ์ถœ์ž์—๊ฒŒ ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค.
  • sleep()์€ ํ•ญ์ƒ ํ˜„์žฌ ํƒœ์Šคํฌ๋ฅผ ์ผ์‹œ ์ค‘๋‹จํ•ด์„œ ๋‹ค๋ฅธ ํƒœ์Šคํฌ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

๋™์‹œ์— ํƒœ์Šคํฌ ์‹คํ–‰ํ•˜๊ธฐ

asyncio.gather(*aws, loop=None, return_exceptions=False)
  • aws ์‹œํ€€์Šค์— ์žˆ๋Š” ์–ด์›จ์ดํ„ฐ๋ธ” ๊ฐ์ฒด๋ฅผ ๋™์‹œ์— ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. aws์— ์žˆ๋Š” ์–ด์›จ์ดํ„ฐ๋ธ”์ด ์ฝ”๋ฃจํ‹ด์ด๋ฉด ์ž๋™์œผ๋กœ ํƒœ์Šคํฌ๋กœ ์˜ˆ์•ฝ๋ฉ๋‹ˆ๋‹ค. ๋ชจ๋“  ์–ด์›จ์ดํ„ฐ๋ธ”์ด ์„ฑ๊ณต์ ์œผ๋กœ ์™„๋ฃŒ๋˜๋ฉด, ๊ฒฐ๊ณผ๋Š” ๋ฐ˜ํ™˜๋œ ๊ฐ’๋“ค์ด ํ•ฉ์ณ์ง„ ๋ฆฌ์ŠคํŠธ์ž…๋‹ˆ๋‹ค. ๊ฒฐ๊ด๊ฐ’์˜ ์ˆœ์„œ๋Š” aws์— ์žˆ๋Š” ์–ด์›จ์ดํ„ฐ๋ธ”์˜ ์ˆœ์„œ์™€ ์ผ์น˜ํ•ฉ๋‹ˆ๋‹ค.
  • return_exceptions๊ฐ€ False(๊ธฐ๋ณธ๊ฐ’)๋ฉด, ์ฒซ ๋ฒˆ์งธ ๋ฐœ์ƒํ•œ ์˜ˆ์™ธ๊ฐ€ gather()๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋Š” ํƒœ์Šคํฌ๋กœ ์ฆ‰์‹œ ์ „ํŒŒ๋ฉ๋‹ˆ๋‹ค. aws ์‹œํ€€์Šค์˜ ๋‹ค๋ฅธ ์–ด์›จ์ดํ„ฐ๋ธ”์€ ์ทจ์†Œ๋˜์ง€ ์•Š๊ณ  ๊ณ„์† ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. return_exceptions๊ฐ€ True๋ฉด, ์˜ˆ์™ธ๋Š” ์„ฑ๊ณต์ ์ธ ๊ฒฐ๊ณผ์ฒ˜๋Ÿผ ์ฒ˜๋ฆฌ๋˜๊ณ , ๊ฒฐ๊ณผ ๋ฆฌ์ŠคํŠธ์— ์ง‘๊ณ„๋ฉ๋‹ˆ๋‹ค.
  • gather()๊ฐ€ ์ทจ์†Œ๋˜๋ฉด, ๋ชจ๋“  ์ œ์ถœ๋œ (์•„์ง ์™„๋ฃŒ๋˜์ง€ ์•Š์€) ์–ด์›จ์ดํ„ฐ๋ธ”๋„ ์ทจ์†Œ๋ฉ๋‹ˆ๋‹ค. aws ์‹œํ€€์Šค์˜ Task๋‚˜ Future๊ฐ€ ์ทจ์†Œ๋˜๋ฉด, ๊ทธ๊ฒƒ์ด CancelledError๋ฅผ ์ผ์œผํ‚จ ๊ฒƒ์ฒ˜๋Ÿผ ์ฒ˜๋ฆฌ๋ฉ๋‹ˆ๋‹ค โ€“ ์ด๋•Œ gather() ํ˜ธ์ถœ์€ ์ทจ์†Œ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์ œ์ถœ๋œ ํƒœ์Šคํฌ/ํ“จ์ฒ˜ ํ•˜๋‚˜๋ฅผ ์ทจ์†Œํ•˜๋Š” ๊ฒƒ์ด ๋‹ค๋ฅธ ํƒœ์Šคํฌ/ํ“จ์ฒ˜๋ฅผ ์ทจ์†Œํ•˜๊ฒŒ ๋˜๋Š” ๊ฒƒ์„ ๋ง‰๊ธฐ ์œ„ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด๋ฒคํŠธ ๋ฃจํ”„

์ด๋ฒคํŠธ ๋ฃจํ”„ ์–ป๊ธฐ

asyncio.get_running_loop()
  • ํ˜„์žฌ OS ์Šค๋ ˆ๋“œ์—์„œ ์‹คํ–‰ ์ค‘์ธ ์ด๋ฒคํŠธ ๋ฃจํ”„๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
asyncio.get_event_loop()
  • ํ˜„์žฌ์˜ ์ด๋ฒคํŠธ ๋ฃจํ”„๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
asyncio.set_event_loop(loop)
  • loop๋ฅผ ํ˜„์žฌ OS ์Šค๋ ˆ๋“œ์˜ ํ˜„์žฌ ์ด๋ฒคํŠธ ๋ฃจํ”„๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
asyncio.new_event_loop()
  • ์ƒˆ ์ด๋ฒคํŠธ ๋ฃจํ”„ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

๋ฃจํ”„ ์‹คํ–‰ ๋ฐ ์ค‘์ง€

loop.run_until_complete(future)
  • future(Future์˜ ์ธ์Šคํ„ด์Šค)๊ฐ€ ์™„๋ฃŒํ•  ๋•Œ๊นŒ์ง€ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์ธ์ž๊ฐ€ ์ฝ”๋ฃจํ‹ด ๊ฐ์ฒด ๋ฉด, asyncio.Task๋กœ ์‹คํ–‰๋˜๋„๋ก ๋ฌต์‹œ์ ์œผ๋กœ ์˜ˆ์•ฝ ๋ฉ๋‹ˆ๋‹ค.
loop.close()
  • ์ด๋ฒคํŠธ ๋ฃจํ”„๋ฅผ ๋‹ซ์Šต๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ ๋ฃจํ”„๋Š” ๋ฐ˜๋“œ์‹œ ์‹คํ–‰ ์ค‘์ด์ง€ ์•Š์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ณ„๋ฅ˜ ์ค‘์ธ ๋ชจ๋“  ์ฝœ๋ฐฑ์„ ๋ฒ„๋ฆฝ๋‹ˆ๋‹ค. ์ด ๋ฉ”์„œ๋“œ๋Š” ๋ชจ๋“  ํ๋ฅผ ๋น„์šฐ๊ณ  ์‹คํ–‰๊ธฐ๋ฅผ ์ข…๋ฃŒํ•˜์ง€๋งŒ, ์‹คํ–‰๊ธฐ๊ฐ€ ์™„๋ฃŒํ•  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
profile
BackEnd

0๊ฐœ์˜ ๋Œ“๊ธ€