Подтвердить что ты не робот

Импортировать внутри потока Python

У меня есть некоторые функции, которые интерактивно загружают модули python с помощью __import__

Недавно я наткнулся на статью о "блокировке импорта" на Python, то есть блокировку специально для импорта (а не только для GIL). Но статья была старой, поэтому, возможно, это не так.

Это заставляет меня задуматься о практике импорта в потоке.

  • Безопасны ли потоки import/__import__?
  • Могут ли они создавать мертвые блокировки?
  • Могут ли они вызывать проблемы с производительностью в поточном приложении?

РЕДАКТИРОВАТЬ 12 сентября 2012 г.

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

Знаете ли вы, что блокировка получена, даже если модуль уже импортирован? Если это так, я должен, вероятно, посмотреть в sys.modules, чтобы проверить, был ли модуль уже импортирован, прежде чем делать вызов __import__.

Конечно, это не должно иметь большого значения в CPython, так как в любом случае есть GIL. Однако это может иметь большое значение для других реализаций, таких как Jython или stackless python.

РЕДАКТИРОВАТЬ 19 сентября 2012 г.

О Jython, вот что они говорят в документе:

http://www.jython.org/jythonbook/en/1.0/Concurrency.html#module-import-lock

Python, однако, определяет блокировку импорта модуля, которая реализованный Jython. Эта блокировка приобретается всякий раз, когда импорт любого имя изготовлен. Это верно, идет ли импорт через импорт оператор, эквивалентный __import__ встроенный или связанный код. это важно отметить, что даже если соответствующий модуль уже были импортированы, блокировка импорта модуля все равно будет получена, если только кратко.

Итак, кажется, что было бы целесообразно проверить sys.modules перед импортом, чтобы избежать приобретения блокировки. Как вы думаете?

4b9b3361

Ответ 1

Нормальный импорт является потокобезопасным, поскольку они приобретают блокировку импорта до выполнения и освобождают его после импорта. Если вы добавите свой собственный импорт, используя доступные крючки, обязательно добавьте к нему эту схему блокировки. Доступ к функциям блокировки в Python можно получить с помощью модуля imp (imp.lock_held()/acquire_lock()/release_lock()).

Использование этой блокировки импорта не создаст никаких взаимных ошибок или ошибок зависимостей, кроме круговых зависимостей уже известных.

Низкоуровневый вызов для создания потока clone в Linux, потоки в Python - это операция, подобная fork. Викинг и клонирование применяют различные типы поведения на различных сегментах памяти. Например, только потоки не разделяются потоками, по сравнению с вилками, которые клонируют больше сегментов (данные (часто COW), стек, код, куча), эффективно не разделяя его содержимое. Механизм импорта в Python использует глобальное пространство имен, которое не помещается в стек, используя совместно используемый сегмент с его потоками. Поскольку побочные эффекты (т.е. Изменения в памяти) импорта работают в одних и тех же сегментах, он работает как однопоточная программа. Однако будьте осторожны, чтобы использовать поточнобезопасные библиотеки в вашем импорте для многопоточных программ. Он будет заставлять хаос использовать вызовы функций, которые не являются потокобезопасными в такой среде.

Кстати, потоковые программы на Python страдают GIL, которые не позволят значительно повысить производительность, если ваша программа не связана с I/O или полагаться на C или внешние потокобезопасные библиотеки (поскольку они освобождают GIL перед выполнением). Запуск из двух потоков одна и та же импортированная функция не будет выполняться одновременно из-за этого GIL. Обратите внимание, что это только ограничение CPython, и другие реализации Python будут иметь другое поведение.

Чтобы ответить на ваше редактирование: импортированные модули все кэшируются Python. Если модуль уже загружен в кеш, он не будет запущен снова, и оператор (или функция) импорта сразу вернется. Вам не нужно реализовывать поиск кэша в sys.modules, Python делает это для вас и не будет imp блокировать что-либо, кроме GIL для поиска sys.modules.

Чтобы ответить на второе редактирование: я предпочитаю поддерживать более простой код, чем пытаться оптимизировать вызовы для библиотек, которые я использую (в данном случае, стандартная библиотека). Обоснование заключается в том, что время, требуемое для выполнения чего-либо, обычно намного важнее времени, необходимого для импорта модуля, который это делает. Кроме того, время, необходимое для поддержания такого кода во всем проекте, намного превышает время, необходимое для его выполнения. Все это сводится к: "время программиста более ценно, чем время процессора".