├── .vscode
└── settings.json
├── LICENSE
├── README.md
├── __pycache__
└── multiprocessing.cpython-36.pyc
├── assets
├── GIL.png
├── heap_py.png
├── multi.png
├── process.png
└── single.png
├── multi_process.py
├── multi_threaded.py
└── single_thread.py
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "python.pythonPath": "/usr/bin/python3"
3 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Wellington R
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | GIL em Python
6 |
7 |
8 |
9 | O que é GIL |
10 | Para que é usado |
11 | Impacto nos programas
12 |
13 |
14 | O que é GIL?
15 |
16 | GIL é o acronimo para _Global Interpreter Lock_.
17 |
18 | O Python _Global Interpreter Lock_, ou simplesmente GIL, é um mutex (ou _lock_) que permite que apenas uma _thread_ tome conta do interpretador Python.
19 | Isso significa que somente uma _thread_ pode estar em um estado de execução em qualquer ponto do tempo.
20 |
21 | ___
22 |
23 | Para que é usado?
24 |
25 | Quando é declarado uma variavel em Python, ex: `x = 10`, este não aloca um local de memória onde 10 está armazenado, e sim cria um objeto na memória _heap_ onde x conterá uma referência para o objeto 10.
26 |
27 | No caso de x posteriormente receber None, ex: `x = None`, Python irá verificar que o numero de referências ao objeto, que no caso por agora não conter uma referencia para o mesmo, terá 0 referências, e será setado como _"Dead Object"_ pelo algoritmo _"Garbage Collector"_, (Coletor de lixo).
28 |
29 | > O algoritmo utilizado pelo Garbage Collector do Python é chamado de Reference Counting.
30 | > Você pode obter o numero de contagem de algum argumento atravês do seguinte comando ```sys.getrefcount()```
31 |
32 | O problema é que essa forma de gerenciamento de memória utilizando reference couting precisa de proteção para um fenômeno chamado _'race conditions'_, onde duas _threads_ aumentam ou diminuem seu valor simultaneamente. Pois se isso acontecer, poderá causar problemas de memória, onde poderá nunca excluir um objeto ou até liberação incorreta do mesmo enquanto ainda existe referência, causando _Bugs_.
33 |
34 | Devido a isso é usado o GIL, aplicando a regra de execução de qualquer código Python a _single lock_ previnindo qualquer _Deadlock_ [^1], que por outro lado transforma qualquer código Python em _single-thread_.
35 |
36 | [^1]: _Deadlock_ pode ser traduzido informalmente para Impasse, onde no cenario da Ciência da Computação é usado quando dois ou mais processos ficam impedidos de continuar suas execuções devido um bloqueiar o outro.
37 |
38 | ___
39 |
40 | Impacto nos programas
41 |
42 | * Exemplo 1 [single_thread](single_thread.py):
43 |
44 |
45 |
46 |
47 | ```
48 | $ python single_thread.py
49 | Time taken in seconds - 3.3819386959075928
50 | ```
51 | * Exemplo 2 [multi_threaded](multi_threaded.py):
52 | 2 threads em paralelo
53 |
54 |
55 |
56 |
57 | ```
58 | $ python multi_threaded.py
59 | Time taken in seconds - 4.140527248382568
60 | ```
61 |
62 |
63 | Como foi notado, ambas as versões levam quase a mesma quantidade de tempo para serem concluídas. Na versão _multithread_ custou ainda mais tempo do que na versão _single_, pois o GIL impediu que os _threads_ ligados à CPU fossem executados em paralelo, devido a estrutura de como é feita a interpretação de códigos em Python, exemplificado abaixo.
64 |
65 |
66 |
67 |
68 |
69 | Referente a figura acima podemos notar que _multiprocessing_ está acima do GIL, na qual você usa vários processos em vez de _threads_. Onde cada processo Python obtém seu próprio interpretador Python e espaço na memória. O Python possui um módulo denominado de _multiprocessing_, que nos permite criar processos facilmente como este :
70 |
71 | * Exemplo 3 [multiprocessing](multiprocessing.py):
72 |
73 |
74 |
75 |
76 | ```
77 | $ python multiprocessing.py
78 | Time taken in seconds - 1.8036038875579834
79 | ```
80 | Tivemos uma melhora incrível na performance !!
81 |
82 | Que fique claro que multi-processing são mais 'pesados' que multi-threading.
83 | Ou seja, lembre-se que para cada processo, teremos um ambiente Python próprio e isso pode se tornar um gargalo de memoria.
84 |
85 | Obrigado por ler até aqui, espero que tenha gostado.
86 | ___
87 |
88 | ## :memo: Licença
89 |
90 | Esse projeto está sob a licença MIT. Veja o arquivo [LICENSE](https://github.com/wrtinho/GIL-Python/blob/master/LICENSE) para mais detalhes.
91 |
92 | ---
93 |
94 |
95 | Feito com 💜 by Wellington
96 |
97 |
--------------------------------------------------------------------------------
/__pycache__/multiprocessing.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wellington-tinho/GIL-Python/7cb5e3f89af8a5a2cae97729185169e950a1a530/__pycache__/multiprocessing.cpython-36.pyc
--------------------------------------------------------------------------------
/assets/GIL.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wellington-tinho/GIL-Python/7cb5e3f89af8a5a2cae97729185169e950a1a530/assets/GIL.png
--------------------------------------------------------------------------------
/assets/heap_py.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wellington-tinho/GIL-Python/7cb5e3f89af8a5a2cae97729185169e950a1a530/assets/heap_py.png
--------------------------------------------------------------------------------
/assets/multi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wellington-tinho/GIL-Python/7cb5e3f89af8a5a2cae97729185169e950a1a530/assets/multi.png
--------------------------------------------------------------------------------
/assets/process.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wellington-tinho/GIL-Python/7cb5e3f89af8a5a2cae97729185169e950a1a530/assets/process.png
--------------------------------------------------------------------------------
/assets/single.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wellington-tinho/GIL-Python/7cb5e3f89af8a5a2cae97729185169e950a1a530/assets/single.png
--------------------------------------------------------------------------------
/multi_process.py:
--------------------------------------------------------------------------------
1 | from multiprocessing import Pool
2 | import time
3 |
4 | COUNT = 50000000
5 | def countdown(n):
6 | while n>0:
7 | n -= 1
8 |
9 | if __name__ == '__main__':
10 | pool = Pool(processes=2)
11 | start = time.time()
12 | r1 = pool.apply_async(countdown, [COUNT//2])
13 | r2 = pool.apply_async(countdown, [COUNT//2])
14 | pool.close()
15 | pool.join()
16 | end = time.time()
17 | print('Time taken in seconds -', end - start)
18 |
19 | # output = 'Time taken in seconds - ' 1.8036038875579834
--------------------------------------------------------------------------------
/multi_threaded.py:
--------------------------------------------------------------------------------
1 | # multi_threaded.py
2 | import time
3 | from threading import Thread
4 |
5 | COUNT = 50000000
6 |
7 | def countdown(n):
8 | while n>0:
9 | n -= 1
10 |
11 | t1 = Thread(target=countdown, args=(COUNT//2,))
12 | t2 = Thread(target=countdown, args=(COUNT//2,))
13 |
14 | start = time.time()
15 | t1.start()
16 | t2.start()
17 | t1.join()
18 | t2.join()
19 | end = time.time()
20 |
21 | print('Time taken in seconds -', end - start)
22 |
23 | # output = 'Time taken in seconds - ' 4.140527248382568
--------------------------------------------------------------------------------
/single_thread.py:
--------------------------------------------------------------------------------
1 | # single_threaded.py
2 | import time
3 | from threading import Thread
4 |
5 | COUNT = 50000000
6 |
7 | def countdown(n):
8 | while n>0:
9 | n -= 1
10 |
11 | start = time.time()
12 | countdown(COUNT)
13 | end = time.time()
14 |
15 | print('Time taken in seconds -', end - start)
16 |
17 |
18 | # output = 'Time taken in seconds - ' 3.3819386959075928
--------------------------------------------------------------------------------