11.1 Global Interpreter Lock

Global Interpreter Lock (GIL) — це механізм в інтерпретаторі CPython, який забезпечує, що тільки один потік виконує байт-код Python в будь-який момент часу. GIL запобігає паралельному виконанню потоків, що може негативно впливати на продуктивність багатопотокових програм, особливо на багатоядерних процесорах.

Причини існування GIL

Спрощення управління пам'яттю: GIL спрощує управління пам'яттю і збірку сміття, роблячи Python простішим для реалізації.

Потокобезпечність: GIL запобігає станам гонок, роблячи виконання коду потокобезпечним без необхідності використовувати блокування.

Проблеми, викликані GIL

Обмежена продуктивність: Багатопотокові програми, які виконують обчислювально інтенсивні задачі, не можуть повністю використати переваги багатоядерних процесорів через обмеження GIL.

Викривлення продуктивності: Програми, які активно використовують потоки для виконання задач, можуть стикатися з погіршенням продуктивності через перемикання контексту між потоками.

Зараз існує 4 основних способи «обходу GIL»:

11.2 Використання багатопроцесорності (multiprocessing)

Модуль multiprocessing дозволяє створювати процеси, які виконуються паралельно і не обмежені GIL, так як кожен процес має свій власний інтерпретатор Python і пам'ять.

Приклад:


import multiprocessing

def worker(num):
    print(f'Worker: {num}')
            
def main():
    processes = []
    for i in range(5):
        p = multiprocessing.Process(target=worker, args=(i,))
        processes.append(p)
        p.start()
            
    for p in processes:
        p.join()
            
main()

11.3 Асинхронне програмування

Асинхронне програмування з використанням asyncio дозволяє виконувати задачі паралельно, не блокуючи основний потік. Хоча це не обходить GIL в прямому сенсі, воно дозволяє ефективно використовувати час очікування для виконання інших задач.

Приклад:


import asyncio

async def main():
    await asyncio.sleep(1)
    print('Hello')
            
asyncio.run(main())

11.4 Використання бібліотек з власним управлінням потоками

Деякі бібліотеки, такі як NumPy і SciPy, написані на C і використовують власні механізми управління потоками, що дозволяє їм обходити GIL і ефективно використовувати багатоядерні процесори для обчислень.

Власне, це і є одна з основних причин успіху Python, яким би повільним він не був. Всі складні обчислення переписані на мовах C/C++ і виконуються на всіх ядрах процесора або навіть одразу на ядрах відеокарти. А на сучасних відеокартах тисячі ядер.

Тому вже не важливо, наскільки мова швидка або повільна, якщо всі ресурсомісткі обчислення виконуються зовнішніми бібліотеками або взагалі винесені в віддалені дата-центри.

11.5 Виконання обчислень поза інтерпретатором Python

Використання розширень на C/C++ або інших мовах, які можуть виконувати обчислення поза інтерпретатором Python і потім повертати результат. Це дозволяє уникнути блокування GIL на час виконання інтенсивних обчислень.

Приклад використання Cython:


# example.pyx

def compute(int n):
    cdef int i, result = 0
    for i in range(n):
        result += i
    return result

Компіляція і використання:


cythonize -i example.pyx

import example
print(example.compute(1000000))
undefined
1
Опрос
Асинхронність,  14 уровень,  10 лекция
недоступен
Асинхронність
Асинхронність