GIL์ด๋ ํ์ด์ฌ ์ธํฐํ๋ฆฌํฐ๊ฐ ํ ์ค๋ ๋๋ง ํ๋์ ๋ฐ์ดํธ์ฝ๋๋ฅผ ์คํ ์ํฌ ์ ์๋๋ก ํด์ฃผ๋ Lock์ด๋ค.
๋ค์ ๋งํด, ํ ์ค๋ ๋๋ง์ด ํ์ด์ฌ ์ธํฐํ๋ฆฌํฐ๋ฅผ ์ปจํธ๋กคํ ์ ์๊ฒ ํด์ค๋ค.
ํ๋์ ์ค๋ ๋์ ๋ชจ๋ ์์์ ํ๋ฝํ๊ณ ๊ทธ ํ์๋ Lock์ ๊ฑธ์ด ๋ค๋ฅธ ์ค๋ ๋๋ ์คํํ ์ ์๊ฒ ๋ง๋๋ค.
ํ์ด์ฌ์ GC(Garbage collection)๋ฅผ ์ํด reference counting์ ํตํด ํ ๋น๋ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๊ด๋ฆฌํ๋ค. ํ์ด์ฌ ์ค๋ธ์ ํธ๋ง๋ค ๋ ํผ๋ฐ์ค๋ก ์ฌ์ฉ๋ ํ์๋ฅผ ์ ์ฅํ๊ณ , 0์ด ๋๋ ๊ฒฝ์ฐ ๋ฉ๋ชจ๋ฆฌ์์ ํด์ ํ๋ค. ์ด๊ฒ์ GIL์ฌ์ฉ ์ด์ ์ ๋ฐ์ ํ ์ฐ๊ด์ด ์๋ค.
(๐ Garbage Collection ๊ด๋ จํด์๋ ์ถํ ๊ธ์ ์์ฑํ๋๋ก ํ๊ฒ ๋ค.)
์ฐธ์กฐ ํ์์ ๊ธฐ๋ฐํ์ฌ GC๋ฅผ ์งํํ๋ Python์ ํน์ฑ์, ์ฌ๋ฌ ๊ฐ์ ์ฐ๋ ๋๊ฐ Python ์ธํฐํ๋ฆฌํฐ๋ฅผ ๋์์ ์คํํ๋ฉด Race Condition์ด ๋ฐ์ํ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
Race Condition์ด๋, ํ๋์ ๊ฐ์ ์ฌ๋ฌ ์ฐ๋ ๋๊ฐ ๋์์ ์ ๊ทผํจ์ผ๋ก์จ ๊ฐ์ด ์ฌ๋ฐ๋ฅด์ง ์๊ฒ ์ฝํ๊ฑฐ๋ ์ฐ์ผ ์ ์๋ ์ํ๋ฅผ ๋งํ๋ค. ์ด๋ฌํ ์ํฉ์ ๋ณด๊ณ Thread-safe ํ์ง ์๋ค๊ณ ํํํ๊ธฐ๋ ํ๋ค.
์ฌ๋ฌ ์ฐ๋ ๋๊ฐ Python ์ธํฐํ๋ฆฌํฐ๋ฅผ ๋์์ ์คํํ ์ ์๊ฒ ๋๋ฉด ๊ฐ ๊ฐ์ฒด์ ์ฐธ์กฐ ํ์๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ๊ด๋ฆฌ๋์ง ๋ชปํ ์๋ ์๊ณ , ์ด๋ก ์ธํด GC๊ฐ ์ ๋๋ก ๋์ํ์ง ์์ ์๋ ์๋ค. ์ด๋ฌํ Race Condition์ ๋ฎคํ ์ค(Mutex)๋ฅผ ์ด์ฉํ๋ฉด ์๋ฐฉํ ์ ์๋ค.
๋ฎคํ
์ค(Mutex)๋, ๋ฉํฐ ์ฐ๋ ๋ฉ ํ๊ฒฝ์์ ์ฌ๋ฌ ๊ฐ์ ์ฐ๋ ๋๊ฐ ์ด๋ ํ ๊ณต์ ์์์ ์ ๊ทผ ๊ฐ๋ฅํ ๋ ๊ทธ ๊ณต์ ์์์ ์ ๊ทผํ๊ธฐ ์ํด ๊ฐ์ง๊ณ ์์ด์ผ ํ๋ ์ผ์ข
์ key์ ๊ฐ๋ค.
๋ง์ฝ ํ ์ฐ๋ ๋๊ฐ ์ด๋ ํ ๊ณต์ ์์์ ๋ํ ๋ฎคํ
์ค๋ฅผ ๊ฐ์ง๊ณ ์๋ค๋ฉด, ๋ค๋ฅธ ์ฐ๋ ๋๋ค์ ๊ทธ ๊ณต์ ์์์ ์ ๊ทผํ๊ณ ์ถ์ ๋๋ ๊ทธ ๊ณต์ ์์์ ์ ๊ทผํ๊ณ ์๋ ์ฐ๋ ๋๊ฐ ๋ฎคํ
์ค๋ฅผ ํ์ด์ค ๋๊น์ง๋ ๊ธฐ๋ค๋ ค์ผ ํ๋ค.
import sys
a = []
b = a
print(sys.getrefcount(a)) # 3
์์์ ์ธ๊ธํ๋ฐ์ ๊ฐ์ด, CPU ์ฐ์ฐ์ ๋น์ค์ด ํฐ ์์ ์ ํ ๋ ๋ฉํฐ ์ฐ๋ ๋ฉ์ ์คํ๋ ค ์ฑ๋ฅ์ ๋จ์ด๋จ๋ฆฐ๋ค. ๋ณ๋ ฌ์ ์ธ ์คํ์ ๋ถ๊ฐ๋ฅํ๋ฐ ๊ดํ ๋ฌธ๋งฅ ์ ํ(Context Switching) ๋น์ฉ๋ง ์ก์๋จน๋๋ค.
๊ทธ๋ฌ๋, CPU ์ฐ์ฐ์ ๋น์ค์ด ์ ์, ์ฆ ์ธ๋ถ ์ฐ์ฐ(I/O, Sleep ๋ฑ)์ ๋น์ค์ด ํฐ ์์
์ ํ ๋๋ ๋ฉํฐ ์ฐ๋ ๋ฉ์ด ๊ต์ฅํ ์ข์ ์ฑ๋ฅ์ ๋ณด์ธ๋ค. ๋ฐ๋ผ์ Python์์ ๋ฉํฐ ์ฐ๋ ๋ฉ์ด ๋ฌด์กฐ๊ฑด ์ ์ข๋ค๋ ๋ง์ ์ฌ์ค์ด ์๋๋ค. ์ค์ ๋ก, I/O ํน์ Sleep ๋ฑ์ ์ธ๋ถ ์ฐ์ฐ์ด ๋๋ถ๋ถ์ด๋ผ๋ฉด ๋ฉํฐ ์ฐ๋ ๋ฉ์ ํตํด ํฐ ์ฑ๋ฅ ํฅ์์ ๊ธฐ๋ํ ์ ์๋ค.
์๋์ ์์๋ฅผ ๋ณด๋ฉด ๋ฉํฐ ์ค๋ ๋ฉ์ ํตํด ๋ ๋นจ๋ผ์ง ๊ฒ์ ํ์ธํ ์ ์๋ค.
import threading
import time
def sleep_for_2s():
time.sleep(2)
#Single Thread
start = time.time()
sleep_for_2s()
sleep_for_2s()
end = time.time()
print('[Single Thread] total time : {}'.format(end - start))
# Multi Thread
start = time.time()
thread1 = threading.Thread(target=sleep_for_2s)
thread2 = threading.Thread(target=sleep_for_2s)
thread1.start()
thread2.start()
thread1.join()
thread2.join()
end = time.time()
print('[Multi Thread] total time : {}'.format(end - start))
[Single Thread] total time : 4.006161451339722
[Multi Thread] total time : 2.0036208629608154