0
Введение в потоки
GIL и новый GIL

Андрей Нехайчик
Wargaming.net
Из чего сделана эта презентация
3 доклада David Beazley:
● Inside the Python GIL, июнь 2009
● Inside the New GIL, январь 2...
Немного о потоках
● для распараллеливания однотипных
задач
● используется pthread

Отличия от процессов
● поток – наименьш...
Как работают потоки в идеале
1 ядро
Как работают потоки в идеале
3 ядра
Пример
def count(n):
while n > 0:
n -= 1
t1 = Thread(target=count, args=(100000000, ))
t2 = Thread(target=count, args=(100...
Пример
def count(n):
while n > 0:
n -= 1
t1 = Thread(target=count, args=(100000000, ))
t2 = Thread(target=count, args=(100...
Пример: поиск простых чисел
def is_odd_prime(num):
for multiplier in range(3, num, 2):
if num % multiplier == 0:
return Fa...
Пример: поиск простых чисел
from threading import Thread
...
numbers = [2]
thread1=Thread(target=store_odd_primes, args=(n...
Результаты
Поиск простых чисел до 40000
неоптимальным алгоритмом
Окружение

Последовательное
выполнение

2 потока
(1 ядро)...
Потоки в Python
● Существует GIL и гарантирует
последовательное выполнение байткода
● Каждые 100 тиков: освобождение и зах...
Потоки в Python
Обработка сигналов
Профилирование однопоточной
программы
python -m cProfile prime_seq.py
ncalls
1
1

tottime
0.001
0.015

9999
1229

0.797
0....
Профилирование многопоточной
программы
ncalls tottime percall cumtime percall filename:lineno(function)
………
2

0.000

0.00...
Вернёмся к начальному примеру
def count(n):
while n > 0:
n -= 1
Последовательное

2 потока
(2 ядра)

Разница

python 2.7.5...
Почему такие большие накладные
расходы (1 ядро)?
Почему такие большие накладные
расходы (2 ядра)?
Визуализация попыток захвата
Промежуточные итоги
● Код параллельно не выполняется
● Но IO (всегда) и CPython расширения
(некоторые) освобождают GIL
● Н...
Зачем нужен GIL?
● Защита операций работы с памятью в
ядре
● Упрощение кода
● Скорость выше, если код проще
GIL в python 3.2
● Первое серьёзное изменение со времён
1992 года
● Вместо счётчика тиков - gil_drop_request
● Также добав...
Как это работает?
Проблемы с таймаутом
Проблемы из-за отсутствия
планировщика
Замедление IO
Какие планы по GIL
Его заменят, если новый подход будет:
● простым
● увеличит скорость для многопоточных
программ
● не изм...
Как обойти GIL
● Для IO этого делать не надо
● Использовать специализированные
библиотеки:
https://wiki.python.org/moin/Pa...
Использовать другие
интерпретаторы
Последовательное

2 потока
(2 ядра)

4 потока
(4 ядра)

jython 2.5.3
(Gentoo, i3 3Ghz)
...
Multiprocessing
from multiprocessing import Process, Pipe
…
def store_odd_primes(pipe_conn, max_number, start_number=3):
s...
Multiprocessing
Последовательное

2 процесса
(2 ядра)

4 потока
(4 ядра)

python 2.6.8
(Gentoo, i3 3Ghz)

3.80

2.80 (x1.3...
Выводы
● Параллельной многопоточности в Python
по умолчанию нет
● Она частично существует для
специализированных расширени...
Спасибо.
Upcoming SlideShare
Loading in...5
×

Введение в GIL и новый GIL

457

Published on

Автор: Андрей Нехайчик (Wargaming.net | COOO «Гейм Стрим»)

— Треды, отличия от потоков.
— Как использовать треды.
— Тестирование производительности (и облом).
— Представление GIL, как он работает.
— Освобождение по I/O, 100 тиков.
— Зачем нужен GIL.
— Проблемы переключения потоков (медленный захват).
— Проблема 100 тиков.
— Проблема отсутствия приоритетов и их типов.
— Новый GIL, 5 миллисекунд, drop_request.
— Когда drop_request не работает.
— Соревнование CPU и I/O тредов.
— Как борются с GIL: тезисы о numpy, Jython, multiprocessing.

Published in: Technology
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
457
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
18
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

Transcript of "Введение в GIL и новый GIL"

  1. 1. Введение в потоки GIL и новый GIL Андрей Нехайчик Wargaming.net
  2. 2. Из чего сделана эта презентация 3 доклада David Beazley: ● Inside the Python GIL, июнь 2009 ● Inside the New GIL, январь 2010 ● Understanding the Python GIL, февраль 2010 http://www.dabeaz.com/GIL/ - Специфический внутряк для разработчиков ядра питона + Свежие тесты
  3. 3. Немного о потоках ● для распараллеливания однотипных задач ● используется pthread Отличия от процессов ● поток – наименьшая единица обработки ● поток – составной элемент процесса ● потоки работают в едином адресном пространстве ● потоки “дешевле” и, обычно, ОС проще ими манипулировать
  4. 4. Как работают потоки в идеале 1 ядро
  5. 5. Как работают потоки в идеале 3 ядра
  6. 6. Пример def count(n): while n > 0: n -= 1 t1 = Thread(target=count, args=(100000000, )) t2 = Thread(target=count, args=(100000000, )) t1.start() t2.start() t1.join() t2.join()
  7. 7. Пример def count(n): while n > 0: n -= 1 t1 = Thread(target=count, args=(100000000, )) t2 = Thread(target=count, args=(100000000, )) t1.start() t2.start() t1.join() t2.join() прекратите тиражировать бесполезный пример
  8. 8. Пример: поиск простых чисел def is_odd_prime(num): for multiplier in range(3, num, 2): if num % multiplier == 0: return False return True def store_odd_primes(storage, max_number, start_number=3): for num in range(start_number, max_number + 1, 2): if is_odd_prime(num): storage.append(num) numbers = [2] store_odd_primes(numbers, 20000) store_odd_primes(numbers, 40000, start_number=20001) print len(numbers)
  9. 9. Пример: поиск простых чисел from threading import Thread ... numbers = [2] thread1=Thread(target=store_odd_primes, args=(numbers, 20000, )) thread1.start() thread2=Thread(target=store_odd_primes, args=(numbers, 40000, ), kwargs={'start_number': 20001}) thread2.start() thread1.join() thread2.join() print len(numbers)
  10. 10. Результаты Поиск простых чисел до 40000 неоптимальным алгоритмом Окружение Последовательное выполнение 2 потока (1 ядро) 2 потока (2 ядра) python 2.7.5 (2GHz, Gentoo) 5.40 5.41 5.92 (+10%) python 3.2.5 8.80 9.02 12.11 (+40%) python 3.3.3 8.90 8.90 12.20 (+40%) python 2.7.3 (1GHz, iOS 7, iPad 3) 23.90 - 25.30 (+5%) python 2.7.2 (2.5GHz, OS X 10.8) 3.56 - 3.90 (+10%)
  11. 11. Потоки в Python ● Существует GIL и гарантирует последовательное выполнение байткода ● Каждые 100 тиков: освобождение и захват GIL ● 1 тик – одна или более инструкций байткода ● IO освобождает GIL ● Си-модули могут освобождать GIL ● Освобождение и захват GIL – дополнительные накладные расходы
  12. 12. Потоки в Python
  13. 13. Обработка сигналов
  14. 14. Профилирование однопоточной программы python -m cProfile prime_seq.py ncalls 1 1 tottime 0.001 0.015 9999 1229 0.797 0.001 1 0.000 # 10000 filename:lineno(function) prime_seq.py:1(<module>) prime_seq.py:3 (get_prime_list) prime_seq.py:5(is_prime) {method 'append' of 'list' objects} {method 'disable' of '_lsprof.Profiler' objects}
  15. 15. Профилирование многопоточной программы ncalls tottime percall cumtime percall filename:lineno(function) ……… 2 0.000 0.000 0.886 0.443 threading.py:909(join) 25 0.886 0.035 0.886 0.035 {method 'acquire' of 'thread.lock'} 97 0.000 0.000 0.000 0.000 {method 'append' of 'list'} 1 0.000 0.000 0.000 0.000 {method 'disable' of ……… '_lsprof.Profiler'} 2 0.000 0.000 0.000 0.000 {method 'extend' of 'list'} 2 0.000 0.000 0.000 0.000 {method 'get' of 'dict'} 1 0.000 0.000 0.000 0.000 {method 'insert' of 'list'} 2 0.000 0.000 0.000 0.000 {method 'items' of 'dict'} 1 0.000 0.000 0.000 0.000 {method 'lower' of 'str'} 12 0.000 0.000 0.000 0.000 {method 'release' of 'thread.lock'} 1 0.000 0.000 0.000 0.000 {method 'rfind' of 'str'} 2 0.000 0.000 0.000 0.000 {method 'setter' of 'property'} 6 0.000 0.000 0.000 0.000 {method 'write' of 'file'}
  16. 16. Вернёмся к начальному примеру def count(n): while n > 0: n -= 1 Последовательное 2 потока (2 ядра) Разница python 2.7.5, Gentoo, 2Ghz 20.0 27.7 x1.4 python 3.2.5 19.7 34.5 x1.8 David Beazley OS X, 2GHz 24.6 45.5 x1.8 python 2.7.2 OS X 10.8, 2.5 Ghz i5 15.2 23.7 x1.6
  17. 17. Почему такие большие накладные расходы (1 ядро)?
  18. 18. Почему такие большие накладные расходы (2 ядра)?
  19. 19. Визуализация попыток захвата
  20. 20. Промежуточные итоги ● Код параллельно не выполняется ● Но IO (всегда) и CPython расширения (некоторые) освобождают GIL ● Нет планировщика потоков ● Сигналы обрабатываются в главном потоке ● Потоки с интенсивным использованием CPU передерживают GIL ● Провальные попытки захвата GIL
  21. 21. Зачем нужен GIL? ● Защита операций работы с памятью в ядре ● Упрощение кода ● Скорость выше, если код проще
  22. 22. GIL в python 3.2 ● Первое серьёзное изменение со времён 1992 года ● Вместо счётчика тиков - gil_drop_request ● Также добавлен таймаут в 5мс
  23. 23. Как это работает?
  24. 24. Проблемы с таймаутом
  25. 25. Проблемы из-за отсутствия планировщика
  26. 26. Замедление IO
  27. 27. Какие планы по GIL Его заменят, если новый подход будет: ● простым ● увеличит скорость для многопоточных программ ● не изменит скорость для однопоточных ● будет совместим с текущим API ядра ● оставит такое же поведение GC
  28. 28. Как обойти GIL ● Для IO этого делать не надо ● Использовать специализированные библиотеки: https://wiki.python.org/moin/ParallelProcessing (например scipy) ● Использовать другие интерпретаторы ● Использовать multiprocessing
  29. 29. Использовать другие интерпретаторы Последовательное 2 потока (2 ядра) 4 потока (4 ядра) jython 2.5.3 (Gentoo, i3 3Ghz) 10.70 8.65 (x1.24) 6.85 (x1.56) pypy 2.0.2 (Gentoo, i3 3Ghz) 2.75 2.85 2.90
  30. 30. Multiprocessing from multiprocessing import Process, Pipe … def store_odd_primes(pipe_conn, max_number, start_number=3): storage = [] for num in range(start_number, max_number + 1, 2): if is_odd_prime(num): storage.append(num) pipe_conn.send(storage) numbers = [2] parent_conn, child_conn = Pipe() proc1 = Process(target=store_odd_primes, args=(child_conn, 20000, )) proc2 = Process(target=store_odd_primes, args=(child_conn, 40000, ), kwargs={'start_number': 20001}) proc1.start();proc2.start();proc1.join();proc2.join() numbers += parent_conn.recv() numbers += parent_conn.recv() print len(numbers)
  31. 31. Multiprocessing Последовательное 2 процесса (2 ядра) 4 потока (4 ядра) python 2.6.8 (Gentoo, i3 3Ghz) 3.80 2.80 (x1.35) 2.08 (x1.83) python 3.2.5 (Gentoo, i3 3Ghz) 5.05 3.68 (x1.37) 3.10 (x1.63) pypy 2.0.2 (Gentoo, i3 3Ghz) 0.50 0.42 (x1.20) 0.33 (x1.55)
  32. 32. Выводы ● Параллельной многопоточности в Python по умолчанию нет ● Она частично существует для специализированных расширений и операций IO ● GIL почти никогда не мешает ● А когда мешает мы знаем как с этим бороться
  33. 33. Спасибо.
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×