from multiprocessing import Process
multiprocessing λͺ¨λμ νμ΄μ¬μμ λ³λ ¬ μ²λ¦¬λ₯Ό μν΄ μ 곡νλ λͺ¨λ μ€ νλλ‘, λ³λμ νλ‘μΈμ€λ₯Ό μμ±νκ³ κ΄λ¦¬ν μ μλ κΈ°λ₯μ μ 곡νλ€. μ΄ λͺ¨λμ νΉν CPU bound μμ
μ μ ν©νλ©°, Global Interpreter Lock (GIL) λλ¬Έμ λ©ν°μ€λ λ©μ΄ ν¨κ³Όλ₯Ό 보μ΄μ§ λͺ»νλ μν©μμ μ¬μ©νλ©΄ μ’λ€.
Process ν΄λμ€λ κ°κ° λ
립μ μΈ νλ‘μΈμ€λ₯Ό λνλ΄λ ν΄λμ€μ΄λ€. Process μΈμ€ν΄μ€λ₯Ό μμ±νκ³ , μ΄λ₯Ό μμνλ κ²μΌλ‘ μλ‘μ΄ νλ‘μΈμ€λ₯Ό μμ±νκ³ μ€νν μ μλ€.
from multiprocessing import Process
def print_func(num):
for i in range(num):
print("Print number %d" % i)
if __name__ == "__main__":
p = Process(target=print_func, args=(5,)) # Process μΈμ€ν΄μ€ μμ±
p.start() # μλ‘μ΄ νλ‘μΈμ€ μμ
p.join() # νλ‘μΈμ€μ μ’
λ£λ₯Ό κΈ°λ€λ¦Ό
Python
볡μ¬
μ΄ μ½λλ μλ‘μ΄ νλ‘μΈμ€λ₯Ό μμ±νμ¬ print_func ν¨μλ₯Ό μ€ννλ€. μ΄ ν¨μλ μ λ¬λ°μ μλ§νΌ μ«μλ₯Ό μΆλ ₯νλ€. μ΄μ²λΌ multiprocessing λͺ¨λκ³Ό Process ν΄λμ€λ₯Ό μ¬μ©νλ©΄, μ¬λ¬ νλ‘μΈμ€λ₯Ό λμμ μ€ννλ λ³λ ¬ μ²λ¦¬λ₯Ό μ½κ² ꡬνν μ μλ€.
multiprocessing.Process ν΄λμ€ μ£Όμ μΈμ
β’
target: νλ‘μΈμ€μ μν΄ μ€νλ ν¨μμ΄λ€. μ΄ ν¨μλ λ³λμ νλ‘μΈμ€μμ μ€νλλ©°, ν¨μμ μ΄λ¦λ§ μ λ¬ν΄μΌ ν©λλ€ (κ΄νΈ μμ΄).
β’
args: target ν¨μμ μ λ¬λ μΈμλ€μ ννμ
λλ€. ν¨μκ° μΈμλ₯Ό νμλ‘ νμ§ μλ κ²½μ°μλ μ΄ μΈμλ μ 곡λ μ μμΌλ©°, μ΄ κ²½μ° λΉ ννμ μ¬μ©νλ€.
β’
kwargs: target ν¨μμ μ λ¬λ ν€μλ μΈμλ€μ μ¬μ (dict)μ΄λ€.
β’
name: νλ‘μΈμ€μ μ΄λ¦μ΄λ€. μ΄ μΈμλ μ νμ μ΄λ©°, μ΄λ¦μ΄ μ 곡λμ§ μλ κ²½μ° μλμΌλ‘ "Process-N"κ³Ό κ°μ ννμ μ΄λ¦μ΄ ν λΉλλ€.
β’
daemon: μ΄ μΈμκ° Trueλ‘ μ€μ λλ©΄, ν΄λΉ νλ‘μΈμ€λ λ°λͺ¬ νλ‘μΈμ€λ‘ μ€μ λλ€. λ°λͺ¬ νλ‘μΈμ€λ λΆλͺ¨ νλ‘μΈμ€κ° μ’
λ£λλ©΄ μλμΌλ‘ μ’
λ£λλ νλ‘μΈμ€μ΄λ€.
Value
μλ μ½λλ νλ‘μΈμ€ κ° κ³΅μ λ©λͺ¨λ¦¬(Value)λ₯Ό ꡬνν μμ
# νλ‘μΈμ€ λ©λͺ¨λ¦¬ 곡μ μμ (곡μ μ±κ³΅!)
from multiprocessing import Process, current_process, Value
import os
# μ€ν ν¨μ
def generate_update_number(v : int):
for i in range(50):
v.value += 1
print(current_process().name, "data", v.value)
def main():
# λΆλͺ¨ νλ‘μΈμ€ μμ΄λ
parent_process_id = os.getpid()
# μΆλ ₯
print(f"Parent process ID {parent_process_id}")
# νλ‘μΈμ€ 리μ€νΈ μ μΈ
processes = list()
# νλ‘μΈμ€ λ©λͺ¨λ¦¬ 곡μ λ³μ μ μΈ
share_value = Value('i', 0) # iλ μ μνμ μλ―Έ, 0μ μ΄κΈ°κ°
for _ in range(1,10):
# μμ±
p = Process(target=generate_update_number, args=(share_value,))
# λ°°μ΄μ λ΄κΈ°
processes.append(p)
# μ€ν
p.start()
# Join
for p in processes:
p.join()
# μ΅μ’
νλ‘μΈμ€ λΆλͺ¨ λ³μ νμΈ
print("Final Data(share_value) in parent process", share_value.value)
if __name__ == '__main__':
main()
Python
볡μ¬
main() ν¨μμμ μ°μ processes 리μ€νΈμ μμ νλ‘μΈμ€λ€μ λ΄κ³ , μ΄λ€μ μ€νμν¨λ€.
generate_update_number() ν¨μμμλ, μ λ¬λ°μ Value κ°μ²΄μ λν΄ 50λ²μ λ°λ³΅μ μννλ©°, ν΄λΉ κ°μ²΄μ κ°μ 1μ© λν΄μ€λ€. μ΄ν, νμ¬ νλ‘μΈμ€μ μ΄λ¦κ³Ό ν΄λΉ κ°μ²΄μ κ° μ¦κ° κ²°κ³Όλ₯Ό μΆλ ₯νλ€.
λ§μ§λ§μ join() ν¨μλ₯Ό μ΄μ©νμ¬ μμ νλ‘μΈμ€λ€μ μ€νμ΄ μ’
λ£λ λκΉμ§ λκΈ°νκ³ , μ΅μ’
μ μΌλ‘ share_value κ°μ²΄μ μ΅μ’
κ°μ μΆλ ₯νλ€.
dataκ° κ³΅μ λμ§ λͺ»ν κ²μ νμΈν μ μλ€.
dataκ° λμ λ§μ
λμ΄ 450μ΄ μΆλ ₯λ κ²μ νμΈν μ μλ€.
Pipe
νμ΄μ¬μ multiprocessing λͺ¨λμ Pipe ν¨μλ λ νλ‘μΈμ€ κ°μ μλ°©ν₯ ν΅μ μ κ°λ₯νκ² νλ μ°κ²°μ μμ±νλ€. Pipe ν¨μλ λ κ°μ μ°κ²° κ°μ²΄λ₯Ό λ°ννλλ°, κ° κ°μ²΄λ νμ΄νμ λ λμ λνλΈλ€.
# νλ‘μΈμ€ κ° ν΅μ μ μν νμ΄ν μ¬μ© μμ
from multiprocessing import Process, Pipe
# λ©μμ§λ₯Ό 보λ΄λ ν¨μ
def send_messages(conn, messages):
for message in messages:
print(f"Sending: {message}")
conn.send(message)
conn.close()
# λ©μμ§λ₯Ό λ°λ ν¨μ
def receive_messages(conn, num_messages):
print("Receiving...")
for _ in range(num_messages):
message = conn.recv()
print(f"Received: {message}")
if __name__ == '__main__':
# νμ΄ν μμ±
parent_conn, child_conn = Pipe()
# λ©μμ§ μμ±
messages = ["Hello", "World", "!"]
# λ©μμ§ μ μ‘ νλ‘μΈμ€ μμ±
p1 = Process(target=send_messages, args=(child_conn, messages))
p1.start()
# λ©μμ§ μμ νλ‘μΈμ€ μμ±
p2 = Process(target=receive_messages, args=(parent_conn, len(messages)))
p2.start()
# νλ‘μΈμ€κ° μ’
λ£λ λκΉμ§ κΈ°λ€λ¦Ό
p1.join()
p2.join()
Python
볡μ¬
send_messages() ν¨μλ messages 리μ€νΈμ μλ λ©μμ§λ₯Ό conn.send() λ©μλλ₯Ό μ΄μ©ν΄ 보λ΄λ ν¨μμ΄λ€.
receive_messages() ν¨μλ num_messages νμλ§νΌ conn.recv() λ©μλλ₯Ό μ΄μ©ν΄ λ©μμ§λ₯Ό λ°λ ν¨μμ΄λ€.
Pipe() ν¨μλ₯Ό μ΄μ©νμ¬ parent_connκ³Ό child_conn κ°μ²΄λ₯Ό μμ±ν©λλ€. μ΄ κ°μ²΄λ νμ΄νμ μμͺ½ λμ λνλΈλ€.
send_messages() ν¨μμ receive_messages() ν¨μ κ°κ°μ νλ‘μΈμ€λ‘ μμ±νμ¬ μ€ννλ€.
join() λ©μλλ₯Ό μ΄μ©ν΄ νλ‘μΈμ€κ° μ’
λ£λ λκΉμ§ κΈ°λ€λ¦° λ€, νλ‘μΈμ€κ° μ’
λ£λλ©΄ μ½λκ° μ’
λ£λλ€.
μ΄λ¬ν λ°©μμΌλ‘, Pipeλ₯Ό μ¬μ©νλ©΄ λ νλ‘μΈμ€ κ°μ λ°μ΄ν°λ₯Ό μ½κ² κ΅νν μ μλ€.
Queue
multiprocessing λͺ¨λμ Queue ν΄λμ€λ νλ‘μΈμ€ κ°μ μμ νκ² λ°μ΄ν°λ₯Ό κ΅νν μ μλ λ°©λ²μ μ 곡νλ€. Queue ν΄λμ€λ FIFO (First In, First Out) μ μ±
μ λ°λ₯΄λ νμ€ ν λ°μ΄ν° ꡬ쑰λ₯Ό μ¬μ©νλ€.
Queue ν΄λμ€μ μ£Όμ λ©μλ
β’
put(item): νμ νλͺ©μ μΆκ°νλ€.
β’
get(): νμμ νλͺ©μ μ κ±°νκ³ λ°ννλ€. νκ° λΉμ΄ μμΌλ©΄, νλͺ©μ΄ λμ°©ν λκΉμ§ μ°¨λ¨λλ€.
β’
empty(): νκ° λΉμ΄ μμΌλ©΄ Trueλ₯Ό λ°ννλ€.
β’
full(): νκ° κ½ μ°¨ μμΌλ©΄ Trueλ₯Ό λ°ννλ€.
# νλ‘μΈμ€ κ° ν΅μ μ μν ν
from multiprocessing import Process, Queue
def func(q, message):
q.put(message)
if __name__ == '__main__':
# ν μμ±
q = Queue()
# νλ‘μΈμ€ μμ±
a = Process(target=func, args=(q,[42, None, 'hello']))
b = Process(target=func, args=(q,[111, True, 'world']))
c = Process(target=func, args=(q,"wow"))
a.start()
b.start()
print(q.get()) # prints "[42, None, 'hello']"
print(q.get()) # prints "[111, True, 'world']"
c.start()
a.join()
b.join()
print(q.get()) # prints "wow"
c.join()
Python
볡μ¬
Queue κ°μ²΄λ μλ£κ΅¬μ‘°μμ λ§νλ ν(queue)μ μ μ¬ν κ°λ
μΌλ‘, λ°μ΄ν°λ₯Ό μ μ₯ν μ μλ 곡κ°μ μ 곡νλ©°, λ°μ΄ν°λ₯Ό μ μ₯ν λμλ put() λ©μλλ₯Ό μ¬μ©νκ³ , λ°μ΄ν°λ₯Ό μΆμΆν λμλ get() λ©μλλ₯Ό μ¬μ©νλ€.
μ μμ μμλ 3κ°μ νλ‘μΈμ€(a, b, c)κ° νλμ Queue κ°μ²΄(q)λ₯Ό 곡μ νκ³ μλ€. λ¨Όμ a νλ‘μΈμ€μ b νλ‘μΈμ€κ° κ°μμ λ°μ΄ν°λ₯Ό qμ μ μ₯νκ³ , λ©μΈ νλ‘μΈμ€μμ μ΄λ₯Ό μμλλ‘ μΆμΆνλ©° μΆλ ₯νλ€. λ§μ§λ§μΌλ‘ c νλ‘μΈμ€κ° qμ λ°μ΄ν°λ₯Ό μ μ₯νκ³ , μ΄λ₯Ό λ©μΈ νλ‘μΈμ€μμ μΆμΆνλ©° μΆλ ₯νλ€.
Queue κ°μ²΄λ₯Ό μ΄μ©νλ©΄ 볡μ‘ν νλ‘μΈμ€ κ° ν΅μ μ μ½κ² ꡬνν μ μλ€. λ€λ§, put() λ©μλμ get() λ©μλλ λ°μ΄ν°λ₯Ό μ μ₯νκ³ μΆμΆν λ λΈλ‘νΉ(blocking) λ°©μμΌλ‘ λμνκΈ° λλ¬Έμ, ν μͺ½ νλ‘μΈμ€κ° λ°μ΄ν°λ₯Ό μΆκ°νκ³ μμ λ λ€λ₯Έ μͺ½ νλ‘μΈμ€κ° λ°μ΄ν°λ₯Ό μΆμΆνλ €κ³ νλ©΄, ν΄λΉ νλ‘μΈμ€λ λΈλ‘νΉλμ΄ λκΈ°νκ² λλ€.