Как потоки работают в Python, и каковы общие специфические подводные камни Python-threading?


Я пытаюсь обернуть мою голову вокруг того, как потоки работают в Python, и трудно найти хорошую информацию о том, как они работают. Возможно, мне просто не хватает ссылки или чего-то еще, но похоже, что официальная документация не очень тщательна по этому вопросу, и я не смог найти хорошую запись.

от того, что я могу сказать, только один поток может быть запущен сразу, и активный поток переключается каждые 10 инструкций или так?

где тут хороший объяснение, или вы можете его предоставить? Также было бы очень приятно знать о распространенных проблемах, с которыми вы сталкиваетесь при использовании потоков с Python.

7 75

7 ответов:

да, из-за глобальной блокировки интерпретатора (GIL) может выполняться только один поток за раз. Вот некоторые ссылки с некоторыми идеями об этом:

из последней ссылки интересная цитата:

позвольте мне объяснить, что все это значит. Потоки выполняются внутри одного виртуального машина, а значит и бегать на ней же физическая машина. Процессы могут выполняться на той же физической машине или в еще одна физическая машина. Если вы архитектор всего потоки, вы ничего не сделали для доступа несколько машин. Таким образом, вы можете масштабировать как много ядер на одном машина (которых будет довольно много со временем), но чтобы действительно добраться до интернета весы, вам нужно будет решить проблема с несколькими машинами в любом случае.

Если вы хотите использовать многоядерные, pyprocessing определяет API на основе процесса для выполнения реальной распараллеливания. Элемент PEP также включает в себя некоторые интересные показатели.

Python-довольно простой язык для потоковой передачи, но есть предостережения. Самое большое, что вам нужно знать о глобальной блокировке интерпретатора. Это позволяет только одному потоку получить доступ к интерпретатору. Это означает две вещи: 1) Вы редко когда-либо используете оператор блокировки в python и 2) Если вы хотите воспользоваться преимуществами многопроцессорных систем, вам нужно использовать отдельные процессы. EDIT: я также должен указать, что вы можете поместить часть кода в C/C++, если хотите получить и вокруг Гила тоже.

таким образом, вам нужно пересмотреть, почему вы хотите использовать потоки. Если вы хотите распараллелить приложение, чтобы воспользоваться преимуществами двухъядерного архитектура, нужно сломать ваше приложение на несколько процессов.

Если вы хотите улучшить отзывчивость, вы должны рассмотреть возможность использования потоков. Однако есть и другие альтернативы, а именно microthreading. Есть также некоторые рамки, которые вы должны посмотреть в:

Ниже приведен пример работы с потоками. Он породит 20 потоков; каждый поток выведет свой номер потока. Запустите его и соблюдайте порядок, в котором они печатают.

import threading
class Foo (threading.Thread):
    def __init__(self,x):
        self.__x = x
        threading.Thread.__init__(self)
    def run (self):
          print str(self.__x)

for x in xrange(20):
    Foo(x).start()

как вы намекнули на Python потоки реализуются через время нарезки. Вот как они получают "параллельный" эффект.

в моем примере мой класс Foo расширяет поток, затем я реализую run метод, который является, где код, который вы хотели бы запустить в потоке идет. Чтобы запустить поток вы звоните start() на объект потока, который будет автоматически вызывать run метод...

конечно, это только самые основы. В конечном итоге вы захотите узнать о семафорах, мьютексах и блокировках для синхронизации потоков и передачи сообщений.

используйте потоки в python, если отдельные работники выполняют операции с привязкой ввода-вывода. Если вы пытаетесь масштабировать несколько ядер на машине либо найти хороший IPC рамки для python или выбрать другой язык.

одним из простых решений для GIL является многопроцессорная обработка модуль. Он может быть использован в качестве замены модуля threading, но вместо потоков использует несколько процессов интерпретатора. Из-за этого есть немного больше накладных расходов, чем простой поток для простых вещей, но это дает вам преимущество реальной распараллеливания, если вам это нужно. Он также легко масштабируется на несколько физических машин.

Если вам нужна действительно крупномасштабная распараллеливание, чем я бы посмотрите дальше, но если вы просто хотите масштабироваться до всех ядер одного компьютера или нескольких разных без всей работы, которая пошла бы на реализацию более всеобъемлющей структуры, чем это для вас.

Примечание: везде, где я упоминаю thread Я имею в виду конкретно потоки в python пока явно не указано.

потоки работают немного по-другому в python, если вы исходите из C/C++ фон. В python только один поток может находиться в запущенном состоянии в данный момент времени.Это означает, что потоки в python не могут по-настоящему использовать мощность нескольких процессорных ядер, поскольку по дизайну потоки не могут работать параллельно несколько ядер.

поскольку управление памятью в python не является потокобезопасным, каждый поток требует эксклюзивного доступа к структурам данных в интерпретаторе python.Этот эксклюзивный доступ приобретается механизмом под названием GIL (global interpretr lock).

Why does python use GIL?

чтобы предотвратить одновременный доступ нескольких потоков к состоянию интерпретатора и повреждение интерпретатора государство.

идея заключается в том, когда поток выполняется (даже если это основной поток), Гил приобретен и после некоторого предопределенного интервала времени GIL освобождается текущим потоком и повторно приобретается каким-либо другим потоком( если таковой имеется).

Why not simply remove GIL?

это не то, что его невозможно удалить GIL, его просто в prcoess этого мы в конечном итоге положить mutiple замки внутри интерпретатора для того, чтобы сериализовать доступ, который делает даже однопоточное приложение менее производительным.

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

So when does thread switching occurs in python?

переключатель потока происходит когда Гил released.So когда Гил выйдет на свободу? Есть два сценария, которые необходимо принять во внимание.

если поток выполняет операции, связанные с ЦП(например, изображение обработка.)

в старых версиях python переключение потоков происходило после фиксированного отсутствия python instructions.It по умолчанию было установлено значение 100.оказалось, что это не очень хорошая политика, чтобы решить, когда переключение должно произойти, так как время, потраченное на выполнение одной инструкции, может очень дико от миллисекунды до даже секунды.Поэтому выпускать Гил после каждого 100 инструкции независимо от времени они принимают исполнять-это плохая политика.

в новых версиях вместо использования количества команд в качестве метрики для переключения потока используется настраиваемый интервал времени. Интервал переключения по умолчанию составляет 5 миллисекунд.вы можете получить текущий интервал переключения с помощью sys.getswitchinterval(). Это можно изменить с помощью sys.setswitchinterval()

если поток делает некоторые Io связаны Операции(например, доступ к файловой системе или
сеть ИО)

Gil освобождается всякий раз, когда поток ждет завершения операции ввода-вывода.

Which thread to switch to next?

интерпретатор не имеет своего собственного планировщика.какой поток становится запланированным в конце интервала-это решение операционной системы. .

постарайтесь помнить, что GIL настроен на опрос вокруг так часто, чтобы сделать показать внешний вид нескольких задач. Этот параметр можно точно настроить, но я предлагаю предложение о том, что должна быть работа, которую выполняют потоки, или множество переключателей контекста вызовут проблемы.

Я бы зашел так далеко, чтобы предложить несколько родителей на процессорах и попытаться сохранить подобные задания на одном ядре(ядрах).