λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
Language/Python

[Python] Thread & Lock ( μ“°λ ˆλ“œμ™€ 락 ) | LIM

by forestlim 2022. 6. 15.
728x90
λ°˜μ‘ν˜•

πŸ“Œ Thread(μŠ€λ ˆλ“œ)λž€?

μŠ€λ ˆλ“œ(thread)λž€ ν”„λ‘œμ„ΈμŠ€(process) λ‚΄μ—μ„œ μ‹€μ œλ‘œ μž‘μ—…μ„ μˆ˜ν–‰ν•˜λŠ” 주체λ₯Ό μ˜λ―Έν•œλ‹€.
ν•œ ν”„λ‘œμ„ΈμŠ€ λ‚΄μ—μ„œ μ—¬λŸ¬ 개의 μž‘μ—…λ“€μ΄ λ™μ‹œμ— 싀행될 수 μžˆμ–΄μ•Ό ν•˜λŠ”λ° 이것이 μŠ€λ ˆλ“œμ΄λ‹€.
μŠ€λ ˆλ“œλŠ” ν”„λ‘œμ„ΈμŠ€κ°€ 가지고 μžˆλŠ” λ©”λͺ¨λ¦¬λ₯Ό κ³΅μœ ν•œλ‹€. 

λ˜ν•œ, 두 개 μ΄μƒμ˜ μŠ€λ ˆλ“œλ₯Ό κ°€μ§€λŠ” ν”„λ‘œμ„ΈμŠ€λ₯Ό λ©€ν‹°μŠ€λ ˆλ“œ ν”„λ‘œμ„ΈμŠ€(multi-threaded process)라고 ν•œλ‹€.

파이썬 ν”„λ‘œκ·Έλž¨μ€ 기본적으둜 ν•˜λ‚˜μ˜ μ“°λ ˆλ“œ(single thread)μ—μ„œ μ‹€ν–‰λœλ‹€.(파이썬의 GIL μ •μ±…) λ”°λΌμ„œ μ½”λ“œλ₯Ό λ³‘λ ¬λ‘œ μ‹€ν–‰ν•˜κΈ° μœ„ν•΄μ„œλŠ” λ³„λ„μ˜ μ“°λ ˆλ“œλ₯Ό 생성해야 ν•˜λŠ”λ°, 파이썬 μ“°λ ˆλ“œλ₯Ό μƒμ„±ν•˜κΈ° μœ„ν•΄μ„œλŠ” threadingλͺ¨λ“ˆμ„ μ‚¬μš©ν•  수 μžˆλ‹€. 

 

κ·Έλ ‡λ‹€λ©΄ ν”„λ‘œμ„ΈμŠ€μ™€ μŠ€λ ˆλ“œμ˜ μ°¨μ΄λŠ” 무엇인가?

 

ν”„λ‘œμ„ΈμŠ€λŠ” ν”„λ‘œκ·Έλž¨μ΄ μ‹€ν–‰λ˜μ„œ λŒμ•„κ°€κ³  μžˆλŠ” μƒνƒœλΌκ³  μƒκ°ν•˜λ©΄ λœλ‹€. 즉, μ‚¬μš©μžκ°€ μž‘μ„±ν•œ ν”„λ‘œκ·Έλž¨μ΄ μš΄μ˜μ²΄μ œμ— μ˜ν•΄ λ©”λͺ¨λ¦¬ 곡간을 ν• λ‹Ήλ°›μ•„ 싀행쀑인 것을 λ§ν•œλ‹€. μ΄λŸ¬ν•œ ν”„λ‘œμ„ΈμŠ€λŠ” ν”„λ‘œκ·Έλž¨μ— μ‚¬μš©λ˜λŠ” 데이터와 λ©”λͺ¨λ¦¬ λ“±μ˜ μžμ› 그리고 μŠ€λ ˆλ“œλ‘œ κ΅¬μ„±λœλ‹€.

 

ν”„λ‘œμ„ΈμŠ€μ™€ μŠ€λ ˆλ“œλŠ” 처리 방식 에 차이가 μžˆλŠ” 거라고 μƒκ°ν•˜λ©΄ λœλ‹€.

 

βœ… ν”„λ‘œμ„ΈμŠ€

- ν•œ ν”„λ‘œμ„ΈμŠ€λŠ” 맀번 ν•˜λ‚˜μ˜ 둜그인만 μ²˜λ¦¬ν•  수 있기 λ•Œλ¬Έμ— λ™μ‹œμ— μ²˜λ¦¬ν•  μˆ˜κ°€ μ—†λ‹€.

 

- ν”„λ‘œμ„ΈμŠ€λŠ” κ°μžκ°€ κ³ μœ ν•œ λ©”λͺ¨λ¦¬ μ˜μ—­μ„ 가지기 λ•Œλ¬Έμ— μŠ€λ ˆλ“œμ— λΉ„ν•˜λ©΄ λ©”λͺ¨λ¦¬ μ‚¬μš©μ΄ λŠ˜μ–΄λ‚œλ‹€λŠ” 단점이 μžˆμ§€λ§Œ, 이 방식을 톡해 μ‹±κΈ€ λ¨Έμ‹  μ•„ν‚€ν…μ²˜λ‘œλΆ€ν„° μ—¬λŸ¬ 머신을 μ‚¬μš©ν•˜λŠ” λΆ„μ‚° μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μœΌλ‘œ μ‰½κ²Œ μ „ν™˜ κ°€λŠ₯

 

- ν”„λ‘œμ„ΈμŠ€μ˜ μ˜ˆμ‹œλŠ” κ΅¬κΈ€ν¬λ‘¬μ˜ 탭을 μƒκ°ν•˜λ©΄ λœλ‹€.

    - ν•œ 탭에 λ¬Έμ œκ°€ 생겨도 λ‹€λ₯Έ 탭에 영ν–₯이 μ—†λ‹€.

 

βœ…  μŠ€λ ˆλ“œ

- ν•œ ν”„λ‘œμ„ΈμŠ€ λ‚΄μ—μ„œ μ—¬λŸ¬κ°œμ˜ μŠ€λ ˆλ“œλ‘œ μž‘μ—…μ„ μ²˜λ¦¬ν•˜λŠ” 것(λ©€ν‹°μŠ€λ ˆλ“œ)

   ex) pycharmμ—μ„œ μΆ”μ²œμ½”λ“œλ„ 보여주고 μ‹€ν–‰ν•˜λŠ” λ™μ‹œμ— λ””λ²„κΉ…ν•˜λ©΄μ„œ μˆ˜μ •ν•˜λŠ” 것

 

- μŠ€λ ˆλ“œμ˜ μ˜ˆμ‹œλ‘œλŠ” μœˆλ„μš° 탭을 생각해보면 λœλ‹€.

   - ν•œ 탭에 λ¬Έμ œκ°€ 생기면 λͺ¨λ“  탭에 영ν–₯을 미쳐 전체가 κΊΌμ§€κ²Œ λœλ‹€.

 

πŸ“Œ Lockμ΄λž€

Lock 은 python threading νŒ¨ν‚€μ§€μ—μ„œ μ§€μ›ν•œλ‹€.

lock을 acquire() ν•˜λ©΄ ν•΄λ‹Ή μŠ€λ ˆλ“œλ§Œ 곡유 데이터에 μ ‘κ·Όν•  수 있고, lock을 release() ν•΄μ•Όλ§Œ λ‹€λ₯Έ μŠ€λ ˆλ“œμ—μ„œ 곡유 데이터에 μ ‘κ·Όν•  수 μžˆλ‹€. 

Lock을 μ‚¬μš©ν•˜λŠ” μ΄μœ λŠ” ν•˜λ‚˜μ˜ μ“°λ ˆλ“œλ§Œ μ§„μž…ν•˜κ²Œ ν•˜λ„λ‘ ν•˜κΈ° μœ„ν•΄μ„œμ΄λ‹€. λ‚΄κ°€ Lock을 μ‚¬μš©ν–ˆλ˜ μ΄μœ λŠ” λ‹€μŒκ³Ό κ°™λ‹€. I/O μž‘μ—…μ„ μ‹€ν–‰ν•  λ•Œ 파이썬의 GIL(Global Interpreter Lock) μ •μ±…κ³Ό λ‹€λ₯΄κ²Œ μ—¬λŸ¬ 개의 μŠ€λ ˆλ“œλ₯Ό μ‚¬μš©ν•΄μ„œ λ™μ‹œμ²˜λ¦¬λ₯Ό μ§„ν–‰ν•˜λŠ”λ° κ·Έλ•Œ thread1이 μ—…λ°μ΄νŠΈ 해놓은 global λ³€μˆ˜μ— λŒ€ν•΄μ„œ 24μ‹œκ°„ λ™μ•ˆμ€ μœ μ§€λ˜κ²Œ 해두고 μ‹Άμ—ˆκΈ° λ•Œλ¬Έμ΄λ‹€. 즉, λ™μ‹œμ— thread1κ³Ό thread2κ°€ 곡유 λ³€μˆ˜μ— μ ‘κ·Όν•΄μ„œ μ€‘λ³΅μœΌλ‘œ μ—…λ°μ΄νŠΈκ°€ λ˜μ§€ μ•Šκ²Œ ν•˜κΈ° μœ„ν•΄μ„œ μ‚¬μš©ν–ˆλ‹€.

 

파이썬의 GIL μ •μ±… λ•Œλ¬Έμ— νŒŒμ΄μ¬μ€ μ‹±κΈ€μŠ€λ ˆλ“œ μ–Έμ–΄λ‘œ λΆˆλ¦¬μ§€λ§Œ κ°•μ œλ‘œ threadλ₯Ό μƒμ„±ν•΄μ„œ Lock ν…ŒμŠ€νŠΈλ₯Ό μ§„ν–‰ν•΄λ³΄μ•˜λ‹€.

 

1. thread 2개 생성, Lock 미적용

import threading
import time

shared_number = 0


def thread_1(number):
    global shared_number
    print("thread_1 number = ", end=""), print(number)

    for i in range(number):
        shared_number += 1


def thread_2(number):
    global shared_number
    print("thread_2 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=(10000000,)) #천만
    t1.start()
    threads.append(t1)

    t2 = threading.Thread(target=thread_2, args=(10000000,)) #천만
    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_1 number = 10000000
    thread_2 number = 10000000
    --- 0.8049440383911133 seconds ---
    shared_number=12506270
    end of main

threadλ₯Ό 2개 μƒμ„±ν•˜κ³  shared_number에 λŒ€ν•΄ Lock을 μ μš©ν•˜μ§€ μ•Šμ€ μƒνƒœμ—μ„œ 결과값은 μ˜ˆμƒν–ˆλ˜ 20,000,000 κ³ΌλŠ” λ‹€λ₯΄κ²Œ λ‚˜μ˜¨λ‹€. 

κ·Έ μ΄μœ λŠ” 같은 λ³€μˆ˜λ₯Ό λ™μ‹œμ— μ ‘κ·Όν–ˆκΈ° λ•Œλ¬Έμ΄λ‹€.

 

 

2. thread2개 생성, Lock 적용

import threading
import time

shared_number = 0
lock = threading.Lock()  # threadingμ—μ„œ Lock ν•¨μˆ˜ κ°€μ Έμ˜€κΈ°


def thread_1(number):
    global shared_number
    print("thread_1 number = ", end=""), print(number)

    lock.acquire()  # μž‘μ—…μ΄ λλ‚˜κΈ° μ „κΉŒμ§€ λ‹€λ₯Έ μ“°λ ˆλ“œκ°€ κ³΅μœ λ°μ΄ν„° 접근을 κΈˆμ§€
    for i in range(number):
        shared_number += 1
    lock.release()  # lock ν•΄μ œ


def thread_2(number):
    global shared_number
    print("thread_2 number = ", end=""), print(number)

    lock.acquire()  # thread_2 잠금
    for i in range(number):
        shared_number += 1
    lock.release()  # thread_2 ν•΄μ œ


if __name__ == "__main__":

    threads = []

    start_time = time.time()
    t1 = threading.Thread(target=thread_1, args=(10000000,)) #천만
    t1.start() # start() ν•¨μˆ˜λ‘œ μ“°λ ˆλ“œλ₯Ό μ‹œμž‘
    threads.append(t1)

    t2 = threading.Thread(target=thread_2, args=(10000000,)) #천만
    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_1 number = 10000000
    thread_2 number = 10000000
    --- 0.7583627700805664 seconds ---
    shared_number=20000000
    end of main

shared_numberλ₯Ό Lock을 톡해 μ“°λ ˆλ“œλ₯Ό λ™κΈ°ν™”μ‹œμΌœμ£Όμ—ˆκ³  κ·Έ κ²°κ³Ό μ •ν™•ν•œ κ°’(20,000,000)을 μ–»κ²Œλ˜μ—ˆλ‹€.

 

 



πŸ“š μ°Έκ³ 

https://velog.io/@kho5420/Python-Thread-and-Lock-%EC%93%B0%EB%A0%88%EB%93%9C%EC%99%80-%EB%9D%BD

 

[Python] Thread and Lock (μ“°λ ˆλ“œμ™€ 락)

μ“°λ ˆλ“œ(Thread)λŠ” ν”„λ‘œκ·Έλž¨μ˜ μ‹€ν–‰ νλ¦„μž…λ‹ˆλ‹€. ν•˜λ‚˜μ˜ ν”„λ‘œμ„ΈμŠ€ μ•ˆμ—μ„œ μ—¬λŸ¬ 개의 μ“°λ ˆλ“œλ₯Ό λ§Œλ“€ 수 μžˆμŠ΅λ‹ˆλ‹€. ν”„λ‘œμ„ΈμŠ€λž€ 말은 λ©”λͺ¨λ¦¬μ— ν• λ‹Ήλ˜μ–΄ μžˆλŠ” ν•œ 개의 ν”„λ‘œκ·Έλž¨μ„ μ˜λ―Έν•˜κ³ , ν”„λ‘œκ·Έλž¨

velog.io

https://nowonbun.tistory.com/667

 

[Python] μ“°λ ˆλ“œ(Thread)κ³Ό lock 그리고 λ°λ“œλ½

μ•ˆλ…•ν•˜μ„Έμš”. λͺ…μ›”μž…λ‹ˆλ‹€. 이 글은 Pythonμ—μ„œ μ“°λ ˆλ“œ(Thread)κ³Ό lock 그리고 λ°λ“œλ½μ— κ΄€ν•œ κΈ€μž…λ‹ˆλ‹€. μ“°λ ˆλ“œ(Thread)λž€ ν”„λ‘œμ„ΈμŠ€ μ•ˆμ—μ„œ μ›€μ§μ΄λŠ” κ°€μž₯ μ΅œμ†Œ λ‹¨μœ„λ₯Ό μ“°λ ˆλ“œλΌκ³  ν•©λ‹ˆλ‹€. μ΄λ ‡κ²Œ ν‘œν˜„ν•˜

nowonbun.tistory.com

 

728x90
λ°˜μ‘ν˜•

λŒ“κΈ€