Но это настолько важно, что должно обсуждаться в отдельной теме!Olej писал(а): Вот перевод такой ужасной статьи David Beazley Как устроен GIL в Python:Это относительно реализации потоков в Python, глобальной блокировки GIL ((Global Interpreter Lock), и выполнение на многопроцессорных (многоядерных) системах.18 февраля 2010 в 12:29
Как устроен GIL в Python
В которой утверждается и объясняется:Т.е. что выполнение в несколько потоков на многоядерном компьютере может быть медленнее, чем на одном ядре (на одном процессоре)!Следующие результаты получены на двухъядерном MacBook:
последовательный запуск — 24,6 с
параллельный запуск — 45,5 с (почти в 2 раза медленнее!)
параллельный запуск после отключения одного из ядер — 38,0 с
Python - параллелизм
Модератор: Olej
- Olej
- Писатель
- Сообщения: 21338
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Python - параллелизм
Это обсуждение переползло сюда из другой темы, вот отсюда: Python:
- Olej
- Писатель
- Сообщения: 21338
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: Python - параллелизм
Проблема вот в чём (цитирую по статье ... но то же упоминается и в справочнике по Python):Olej писал(а):Olej писал(а): Вот перевод такой ужасной статьи David Beazley Как устроен GIL в Python:18 февраля 2010 в 12:29
Как устроен GIL в Python
Код: Выделить всё
При создании поток просто выполняет метод run() объекта Thread или любую заданную функцию:
...
На самом деле происходит гораздо большее. Python создает маленькую структуру данных (PyThreadState), в которой указаны: текущий stack frame в коде Python,
текущая глубина рекурсии, идентификатор потока, некоторая информация об исключениях. Структура занимает менее 100 байт. Затем запускается новый поток (pthread),
в котором код на языке C вызывает PyEval_CallObject, который запускает то, что указано в Python callable.
Интерпретатор хранит в глобальной переменной указатель на текущий активный поток.
...
Принцип работы прост. Потоки удерживают GIL, пока выполняются. Однако они освобождают его при блокировании для операций ввода-вывода. Каждый раз,
когда поток вынужден ждать, другие, готовые к выполнению, потоки используют свой шанс запуститься.
...
При работе с CPU-зависимыми потоками, которые никогда не производят операции ввода-вывода, интерпретатор периодически проводит проверку
(«the periodic check»). По умолчанию это происходит каждые 100 «тиков», но этот параметр можно изменить с помощью sys.setcheckinterval().
Интервал проверки — глобальный счетчик, абсолютно независимый от порядка переключения потоков.
...
Ожидающий поток при этом может сделать сотни безуспешных попыток захватить GIL.
Мы видим, что происходит битва за две взаимоисключающие цели. Python просто хочет запускать не больше одного потока в один момент.
А операционная система («Ооо, много ядер!») щедро переключает потоки, пытаясь извлечь максимальную выгоду из всех ядер.
- Виктория
- Писатель
- Сообщения: 113
- Зарегистрирован: 28 дек 2012, 14:05
- Откуда: Самара
- Контактная информация:
Re: Python - параллелизм
И какой выход? Свой диспетчер потоков (в статье ведь этот путь не отвергается)? Например, для вычислительных задач на многоядерном процессоре
- Olej
- Писатель
- Сообщения: 21338
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: Python - параллелизм
Прежде всего...Виктория писал(а):И какой выход? Свой диспетчер потоков (в статье ведь этот путь не отвергается)? Например, для вычислительных задач на многоядерном процессоре
1. нужно проверить детально и понять: что и как происходит?
2. могут быть существенные различия проявления а). в операционных системах и б). версиях Python (где-то высказывались мнения, что начиная с Python 3.2 всё что связано с GIL радикально переписано)
3. ... а потом уже разбираться что и как ...
P.S. Как вариант: при крайнем желании использовать N процессоров (а N=8 уже далеко не редкость), вы вполне можете "размножить" задачу на несколько параллельных процессов. Сложность некоторая здесь будет только в их несколько изощрённом IPC (межпроцессном взаимодействии) и медленностью таких взаимодействий (но эти взаимодействия нужно просто оптимизировать, чтобы они происходили только когда крайне нужно, а не когда попало ). Этот путь будет совершенно естественным для Linux или Solaris, но затруднён для Windows ... но и там я проверю как это можно сделать.
- Olej
- Писатель
- Сообщения: 21338
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: Python - параллелизм
Я повторю здесь свой тестовый пример (с минимальными изменениями), который показывался в исходной теме, откуда всё началось...Olej писал(а):Цитата излишне обширная, но она полностью перекрывает содержимое статьи...
Вот его выполнение на 2-х ядерной машине:
Код: Выделить всё
bash-4.2$ ./mthrs.py
число выполнений 2
число циклов в выполнении 10000000
============ последовательное выполнение ============
время 2.99 секунд
================ параллельные потоки ================
время 3.44 секунд
=============== параллельные процессы ===============
время 1.94 секунд
А если то же попытаться сделать параллельно в 2-х потоках управляемых интерпретатором Python на 2-х ядерном процессоре, то затраченное время становится 3.44 секунды, что на 15% дольше вместо ожидаемых 50% короче!
А вот если те же 2 порции той же работы заказать параллельно в 2-х отдельных процессах, управляемых операционной системой, то затраченное время становится 1.94 секунд, что на 35% (ну не 50% ) быстрее, чем последовательное выполнение.
Чем не шаманский результат?
- Вложения
-
- mthrs.py
- (2.04 КБ) 439 скачиваний
- Виктория
- Писатель
- Сообщения: 113
- Зарегистрирован: 28 дек 2012, 14:05
- Откуда: Самара
- Контактная информация:
Re: Python - параллелизм
Windows вроде больше тяготеет к потокам. Результаты могут быть совсем другие?
Т.е. в споре "потоки vs процессы" даже для параллельного выполнения чисто вычислительных задач побеждают процессы? (например, одновременный поиск по разным направлениям, дифференцирование по нескольким координатам и т.п. ) Хотя, даже для 8 ядер организация параллельных вычислений идет не от данных, а от особенностей требуемых операций, функций. Но это я Вас отвлекла, извиняюсь.
Где бы ещё найти восьмиядерный проц? ))Olej писал(а): P.S. Как вариант: при крайнем желании использовать N процессоров (а N=8 уже далеко не редкость), вы вполне можете "размножить" задачу на несколько параллельных процессов....
Т.е. в споре "потоки vs процессы" даже для параллельного выполнения чисто вычислительных задач побеждают процессы? (например, одновременный поиск по разным направлениям, дифференцирование по нескольким координатам и т.п. ) Хотя, даже для 8 ядер организация параллельных вычислений идет не от данных, а от особенностей требуемых операций, функций. Но это я Вас отвлекла, извиняюсь.
- Olej
- Писатель
- Сообщения: 21338
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: Python - параллелизм
В Windows принципиально нет fork() - клонирования процесса, на котором стоит всё серверное ПО UNIX, поэтому там это одна из основных возможностей...Виктория писал(а):Windows вроде больше тяготеет к потокам. Результаты могут быть совсем другие?
Но моделирование fork() есть в других интерфейсных пакетах под Windows, например Boost (а Boost имеет интерфейс к Python)... не исключено, что и в пакетах Python (а их великое множество!) есть нечто, моделирующее поведение fork().
Результаты могут быть, конечно, очень отличающиеся.
У автора статьи, от которой я оттолкнулся, результаты тоже характером сильно отличаются, у него MacOS, в отличие от моего Linux...
Здесь принципиально то, что процесс "программы на Python" - это не исполнимый машинный код, как C/C++, PASCAL или Modula-2, а байт-код программы в обрамлении исполняющей системы Python (интерпретатора). И переключением потоков ведает именно эта исполняющая система Python, а не операционная система.Виктория писал(а): Т.е. в споре "потоки vs процессы" даже для параллельного выполнения чисто вычислительных задач побеждают процессы? (например, одновременный поиск по разным направлениям, дифференцирование по нескольким координатам и т.п. ) Хотя, даже для 8 ядер организация параллельных вычислений идет не от данных, а от особенностей требуемых операций, функций. Но это я Вас отвлекла, извиняюсь.
- Olej
- Писатель
- Сообщения: 21338
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: Python - параллелизм
У меня нет под рукой 8-ядерного проца ... максимум, что нашлось сразу - это вот это:Виктория писал(а): Где бы ещё найти восьмиядерный проц? ))
Код: Выделить всё
olej@atom:~/2013-WORK$ cat /proc/cpuinfo | grep proc
processor : 0
processor : 1
processor : 2
processor : 3
olej@atom:~/2013-WORK$ cat /proc/cpuinfo | grep 'model name'
model name : Intel(R) Atom(TM) CPU 330 @ 1.60GHz
model name : Intel(R) Atom(TM) CPU 330 @ 1.60GHz
model name : Intel(R) Atom(TM) CPU 330 @ 1.60GHz
model name : Intel(R) Atom(TM) CPU 330 @ 1.60GHz
И стоят там не совсем и свежие (это Ubuntu 10.04):
Код: Выделить всё
olej@atom:~/2013-WORK$ u_n_a_m_e -a
Linux atom 2.6.32-45-generic #100-Ubuntu SMP Wed Nov 14 10:41:11 UTC 2012 i686 GNU/Linux
olej@atom:~/2013-WORK$ python -V
Python 2.6.5
Код: Выделить всё
olej@atom:~/2013-WORK/python/parallel/pytspeed/mthrs$ ./mthrs.py
число выполнений 2
число циклов в выполнении 10000000
============ последовательное выполнение ============
время 6.36 секунд
================ параллельные потоки ================
время 9.80 секунд
=============== параллельные процессы ===============
время 3.45 секунд
Код: Выделить всё
olej@atom:~/2013-WORK/python/parallel/pytspeed/mthrs$ ./mthrs.py -t4 -n5000000
число выполнений 4
число циклов в выполнении 5000000
============ последовательное выполнение ============
время 6.55 секунд
================ параллельные потоки ================
время 10.21 секунд
=============== параллельные процессы ===============
время 2.71 секунд
Но насколько же всё становится лучше для выполнения в 4 независимых процесса!
И для проверки ("контрольный выстрел" ) - тот же объём вычислений, но только в 1 последовательный поток или процесс:
Код: Выделить всё
olej@atom:~/2013-WORK/python/parallel/pytspeed/mthrs$ ./mthrs.py -t1 -n20000000
число выполнений 1
число циклов в выполнении 20000000
============ последовательное выполнение ============
время 6.38 секунд
================ параллельные потоки ================
время 6.49 секунд
=============== параллельные процессы ===============
время 7.07 секунд
- Olej
- Писатель
- Сообщения: 21338
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: Python - параллелизм
Не всё так однозначно...Виктория писал(а):Т.е. в споре "потоки vs процессы" даже для параллельного выполнения чисто вычислительных задач побеждают процессы? (например, одновременный поиск по разным направлениям, дифференцирование по нескольким координатам и т.п. )
1. мы говорим здесь только о параллельности в Python, т.е. то, как исполнением потоков управляет исполняющая система Python...
2. и, получается, что не "даже для параллельного выполнения чисто вычислительных задач", а "исключительно для параллельного выполнения чисто вычислительных задач" ... т.е. для операций требующих блокирования (ввод-вывод, сетевые операции и т.п.) Python должен организовать "параллельное сосуществование" достаточно эффективно.
- Olej
- Писатель
- Сообщения: 21338
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: Python - параллелизм
Вот точно та же программа, но в Windows, её выполнение:Виктория писал(а):Windows вроде больше тяготеет к потокам. Результаты могут быть совсем другие?
Код: Выделить всё
C:\Python-test\pytspeed\mthrs>mthrsw.py
число выполнений 2
число циклов в выполнении 10000000
============ последовательное выполнение ============
время 2.39 секунд
================ параллельные потоки ================
время 2.33 секунд
=============== параллельные процессы ===============
error: create child process
Теперь выполнение в 2-х потоках на 2-х процессорах/ядрах равно (в пределах точности временных измерений) последовательному выполнению того же в 1-м потоке.
Но такое изменение поведения, я думаю (практически уверен!) связано не с Linux/Windows, а с тем, что эти прогоны (Windows) я делаю в Python 3, где и говорили, что что-то с GIL переделали:
Код: Выделить всё
c:\Python-test\pytspeed>python -V
Python 3.3.2
Код: Выделить всё
#print "число выполнений %i" % thrnum
#print "число циклов в выполнении %i" % repnum
print( "число выполнений {0:d}".format( thrnum ) )
print( "число циклов в выполнении {0:d}".format( repnum ) )
...
#print "============ последовательное выполнение ============"
print( "============ последовательное выполнение ============" )
...
#print "время %5.2f секунд" % clc
print( "время {0:.2f} секунд".format( clc ) )
...
P.P.S. Как и должно ожидать, fork() в Windows нет и быть не может...
Но меня удивляет то, что это выразилось не в синтаксической ошибке при обращении к модулю os, а то, что там этот вызов есть, а закончился он ошибкой исполнения!
- Вложения
-
- mthrsw.py
- (2.12 КБ) 462 скачивания
Кто сейчас на конференции
Сейчас этот форум просматривают: нет зарегистрированных пользователей и 5 гостей