Liam
Liam
I'm studying ๐Ÿฅธ

Python GIL, Global interpreter Lock

Python GIL, Global interpreter Lock



๐Ÿ’ก Intro

์˜ค๋Š˜์€ Python์˜ ๊ฐ€์žฅ ํฐ ํŠน์ง•์ค‘ ํ•˜๋‚˜์ธ GIL(Global interpreter Lock)์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. Python์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฐœ๋ฐœ์ž๋ผ๋ฉด ๋ˆ„๊ตฌ๋‚˜ ๋‹ค ํ•œ๋ฒˆ์ฏค์€ ๋“ค์–ด๋ดค์„ ๊ฒƒ์ด๊ณ , ์ € ๋˜ํ•œ GIL์— ๋Œ€ํ•ด ๊ณต๋ถ€ํ•ด ๋ณธ์ ์ด ์žˆ์ง€๋งŒ ๋‹ค์‹œ ํ•œ๋ฒˆ ์ •๋ฆฌํ•ด ๋ณด๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.



๐Ÿ”Ž Python ์ธํ„ฐํ”„๋ฆฌํ„ฐ๋ž€?

์šฐ์„  GIL์ด๋ž€ Global Interpreter Lock์˜ ์•ฝ์ž๋กœ ํŒŒ์ด์ฌ ์ธํ„ฐํ”„๋ฆฌํ„ฐ๊ฐ€ ํ•œ ์“ฐ๋ ˆ๋“œ๋งŒ์ด ํ•˜๋‚˜์˜ ๋ฐ”์ดํŠธ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ๋Š” Lock์ž…๋‹ˆ๋‹ค. ์ฆ‰, Python ์ธํ„ฐํ”„๋ฆฌํ„ฐ๋Š” ํ•œ ๋ฒˆ์— ํ•œ ์“ฐ๋ ˆ๋“œ๋งŒ ์‹คํ–‰๋  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.


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



๐Ÿ”Ž GIL(Global Interpreter Lock)

GIL (Global Interpreter Lock)์„ ๐ŸŒŽPython ์œ„ํ‚ค์—์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ •์˜ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

In CPython, the global interpreter lock, or GIL, is a mutex that protects access to Python objects, preventing multiple threads from executing Python bytecodes at once. The GIL prevents race conditions and ensures thread safety. A nice explanation of ๐ŸŒŽhow the Python GIL helps in these areas can be found here. In short, this mutex is necessary mainly because CPythonโ€™s memory management is not thread-safe.


ํ•ด์„์„ ํ•ด๋ณด๋ฉด, Python์˜ ๊ฐ์ฒด๋“ค์— ๋Œ€ํ•œ ์ ‘๊ทผ์„ ๋ณดํ˜ธํ•˜๋Š” ์ผ์ข…์˜ Mutex๋กœ์„œ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์“ฐ๋ ˆ๋“œ๊ฐ€ ํŒŒ์ด์ฌ ์ฝ”๋“œ๋ฅผ ๋™์‹œ์— ์‹คํ–‰ํ•˜์ง€ ๋ชปํ•˜๋„๋ก ํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, ํ•œ ํ”„๋กœ์„ธ์Šค ๋‚ด์—์„œ Python ์ธํ„ฐํ”„๋ฆฌํ„ฐ๋Š” ํ•œ ์‹œ์ ์— ํ•˜๋‚˜์˜ ์“ฐ๋ ˆ๋“œ์— ์˜ํ•ด์„œ๋งŒ ์‹คํ–‰๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฉ€ํ‹ฐ ์“ฐ๋ ˆ๋”ฉ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋‚˜, ์›๋ž˜ ๋ฉ€ํ‹ฐ ์ฝ”์–ด๋ผ๋ฉด ๋ฉ€ํ‹ฐ ์“ฐ๋ ˆ๋”ฉ ์‹œ์— ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์—ฌ๋Ÿฌ ์ฝ”์–ด ์ƒ์—์„œ ๋ณ‘๋ ฌ์‹คํ–‰๋  ์ˆ˜ ์žˆ๋Š”๋ฐ, Python์—์„œ๋Š” ๊ทธ๋Ÿฌํ•œ ๋ณ‘๋ ฌ ์‹คํ–‰์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.


๊ฐ„๋‹จํ•˜๊ฒŒ ์„ค๋ช…์„ ํ•ด๋ณด์ž๋ฉด, 3๊ฐœ์˜ ์“ฐ๋ ˆ๋“œ๋ฅผ ํ†ตํ•ด ์ž‘์—…์„ ํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ–ˆ์„ ๋•Œ ํ•˜๋‚˜์˜ ์“ฐ๋ ˆ๋“œ์— ๋ชจ๋“  ์ž์›์„ ํ—ˆ๋ฝํ•˜๊ณ  ๊ทธ ํ›„์—๋Š” Lock์„ ๊ฑธ์–ด ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๋Š” ์‹คํ–‰ํ•  ์ˆ˜ ์—†๊ฒŒ ๋ง‰์•„๋ฒ„๋ฆผ์œผ๋กœ์จ, ๊ฐ๊ฐ์˜ ์“ฐ๋ ˆ๋“œ๋Š” GIL์„ ์–ป๊ณ  ๋™์ž‘ํ•˜์ง€๋งŒ ์ด ๋•Œ ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ๋Š” ๋ชจ๋‘ ๋™์ž‘์„ ๋ฉˆ์ถ”๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ๊ทธ๋ฆผ์œผ๋กœ ๋‚˜ํƒ€๋‚ด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.


GIL1.png



๐Ÿ”Ž ๊ทธ๋Ÿผ GIL์ด ์™œ ์ƒ๊ธด๊ฑธ๊นŒ?

Python์—์„œ ๋ชจ๋“  ๊ฒƒ์€ ๊ฐ์ฒด(Object)์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ฐ ๊ฐ์ฒด๋Š” Reference Count๋ฅผ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•œ ํ•„๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

Reference Count๋ž€ ๊ทธ ๊ฐ์ฒด๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” Reference๊ฐ€ ๋ช‡ ๊ฐœ ์กด์žฌํ•˜๋Š”์ง€๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ๊ฒƒ์œผ๋กœ, Python์—์„œ์˜ GC(Garbage Collection)๋Š” ์ด๋Ÿฌํ•œ Reference Count๊ฐ€ 0์ด ๋˜๋ฉด ํ•ด๋‹น ๊ฐ์ฒด๋ฅผ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ์‚ญ์ œ์‹œํ‚ค๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์œผ๋กœ ๋™์ž‘ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.


๋”ฐ๋ผ์„œ ํŒŒ์ด์ฌ์˜ ๋ชจ๋“  ๊ฐ์ฒด๋Š” Reference count, ์ฆ‰ ํ•ด๋‹น ๋ณ€์ˆ˜๊ฐ€ ์ฐธ์กฐ๋œ ์ˆ˜๋ฅผ ์ €์žฅํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒŒ ๋˜๋Š”๋ฐ, ๋ฉ€ํ‹ฐ ์“ฐ๋ ˆ๋“œ์ธ ๊ฒฝ์šฐ ์—ฌ๋Ÿฌ ์“ฐ๋ ˆ๋“œ๊ฐ€ ํ•˜๋‚˜์˜ ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด Reference count๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด์„œ ๋ชจ๋“  ๊ฐ์ฒด์— ๋Œ€ํ•œ lock์ด ํ•„์š”ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.


์ด๋Ÿฌํ•œ ๋น„ํšจ์œจ์„ ๋ง‰๊ธฐ ์œ„ํ•ด์„œ Python์—์„œ GIL์„ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ ๋‹น์‹œ GIL์„ ์„ ํƒํ•ด์•ผ ํ–ˆ๋˜ ์ด์œ ๋Š” ๐ŸŒŽWhat Is the Python Global Interpreter Lock (GIL)? ์—์„œ ์ฐพ์„ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

Python has been around since the days when operating systems did not have a concept of threads. Python was designed to be easy-to-use in order to make development quicker and more and more developers started using it. A lot of extensions were being written for the existing C libraries whose features were needed in Python. To prevent inconsistent changes, these C extensions required a thread-safe memory management which the GIL provided. The GIL is simple to implement and was easily added to Python. It provides a performance increase to single-threaded programs as only one lock needs to be managed. C libraries that were not thread-safe became easier to integrate. And these C extensions became one of the reasons why Python was readily adopted by different communities. As you can see, the GIL was a pragmatic solution to a difficult problem that the CPython developers faced early on in Pythonโ€™s life.



๐Ÿ“š ๊ทธ๋ ‡๋‹ค๋ฉด Python ๋ฉ€ํ‹ฐ์“ฐ๋ ˆ๋”ฉ์€ ๋ฌด์กฐ๊ฑด ๋Š๋ฆด๊นŒ?

CPU ์—ฐ์‚ฐ์˜ ๋น„์ค‘์ด ํฐ ์ž‘์—…์„ ํ•  ๋•Œ, Context Switching์œผ๋กœ ์ธํ•ด ๊ดœํ•œ Cost๋งŒ ์žก์•„๋จน๊ธฐ ๋•Œ๋ฌธ์— ๋ฉ€ํ‹ฐ ์“ฐ๋ ˆ๋”ฉ์€ ์˜คํžˆ๋ ค ์„ฑ๋Šฅ์„ ๋–จ์–ด๋œจ๋ฆฌ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ I/O, Sleep ๋“ฑ์˜ ์™ธ๋ถ€ ์—ฐ์‚ฐ์„ ํ•˜๋Š๋ผ CPU๊ฐ€ ์•„๋ฌด๊ฒƒ๋„ ํ•˜์ง€ ์•Š๊ณ  ๊ธฐ๋‹ค๋ฆฌ๊ธฐ๋งŒ ํ•  ๋•Œ๋Š” ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ๋กœ Context Switching์„ ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.


๊ทธ๋Ÿฌํ•œ ์ด์œ ๋กœ CPU ์—ฐ์‚ฐ์˜ ๋น„์ค‘์ด ์ ์€ I/O, Sleep ๋“ฑ์˜ ์™ธ๋ถ€ ์—ฐ์‚ฐ ๊ฐ™์ด ๋น„์ค‘์ด ํฐ ์ž‘์—…์„ ํ•  ๋•Œ๋Š” ๋ฉ€ํ‹ฐ ์“ฐ๋ ˆ๋”ฉ์ด ๊ต‰์žฅํžˆ ์ข‹์€ ์„ฑ๋Šฅ์„ ๋ณด์—ฌ์ฃผ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ฆ‰, Python ๋ฉ€ํ‹ฐ์“ฐ๋ ˆ๋”ฉ์€ ๋ฌด์กฐ๊ฑด ๋Š๋ฆฌ๋‹ค๋ผ๋Š” ๋ง์€ ๋งž๋Š” ๋ง์ด ์•„๋‹™๋‹ˆ๋‹ค. ๋‹ค์Œ ์˜ˆ์‹œ๋ฅผ ํ†ตํ•ด ์„ค๋ช…์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import random
import threading
import time


def working():
    time.sleep(1)
    max([random.random() for i in range(10000000)])
    time.sleep(1)
    max([random.random() for i in range(10000000)])
    time.sleep(1)


# Single Thread
s_time = time.time()
working()
working()
e_time = time.time()
print(f'{e_time - s_time:.5f}')


# Multi Thread
s_time = time.time()
threads = []
for i in range(2):
    threads.append(threading.Thread(target=working))
    threads[-1].start()

for t in threads:
    t.join()

e_time = time.time()
print(f'{e_time - s_time:.5f}')



์•„๋ž˜์™€ ๊ฐ™์ด ํ™•์—ฐํ•œ ์ฐจ์ด๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


1
2
3
4
5
Single Thread -> 10.77272
Multi Thread -> 7.17564



Single Thread๋Š” sleep์œผ๋กœ ์ธํ•ด ์•„๋ฌด ๊ฒƒ๋„ ๋ชปํ•˜๊ณ  ๋™์ž‘์„ ๋Œ€๊ธฐํ•˜๊ฒŒ ๋˜๊ณ , Multi Thread๋Š” sleep์œผ๋กœ ๋ฉˆ์ถ˜ ์ƒํƒœ์—์„œ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๋กœ Context Switchingํ•˜์—ฌ Single Thread์˜ ํšจ์œจ์„ ๊ฐœ์„ ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.



๋๋งบ์Œ Python์œผ๋กœ ์ž‘์—…ํ•˜๋Š” ๊ฐœ๋ฐœ์ž์˜ ์ž…์žฅ์œผ๋กœ์จ ์ง€๊ธˆ๊นŒ์ง€๋Š” GIL๋กœ ์ธํ•œ ๋ถˆํŽธํ•œ์ ์€ ๋Š๋‚„ ์ˆ˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋œปํ•˜์ง€ ์•Š์€ ๊ณ„๊ธฐ๋กœ ์˜ค๋žœ๋งŒ์— ๋‹ค์‹œ GIL(Global Interpreter Lock)์„ ๊ณต๋ถ€ํ•˜๊ฒŒ ๋˜์—ˆ๋Š”๋ฐ, GIL์— ๋Œ€ํ•œ ์—ญ์‚ฌ์™€ Python์˜ GC์— ๋Œ€ํ•ด ์ถฉ๋ถ„ํžˆ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์—ˆ๋˜๊ฒƒ ๋งŒ์œผ๋กœ๋„ ๋งค์šฐ ์˜๋ฏธ์žˆ๋Š” ์‹œ๊ฐ„์ด์—ˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.๐Ÿ˜Š



[์ฐธ๊ณ ์ž๋ฃŒ]

comments powered by Disqus