Я немного не понимаю, работает ли многопоточность в Python или нет.
Я знаю, что по этому поводу было много вопросов, и я читал многие из них, но все еще не понимаю. Я знаю по собственному опыту и видел, как другие публикуют свои собственные ответы и примеры здесь, в StackOverflow, что многопоточность действительно возможна в Python. Так почему же все продолжают говорить, что Python заблокирован GIL и что одновременно может работать только один поток? Это явно работает. Или есть какое-то различие, которого я здесь не понимаю?
Многие авторы / респонденты также продолжают упоминать, что многопоточность ограничена, потому что не использует несколько ядер. Но я бы сказал, что они по-прежнему полезны, потому что они работают одновременно и, таким образом, быстрее справляются с комбинированной рабочей нагрузкой. Я имею в виду, почему в противном случае мог бы существовать модуль потока Python?
Обновить:
Спасибо за все ответы. Насколько я понимаю, многопоточность будет выполняться только параллельно для некоторых задач ввода-вывода, но может выполняться только по одной для нескольких ядерных задач, связанных с процессором.
Я не совсем уверен, что это означает для меня с практической точки зрения, поэтому я просто приведу пример задачи, которую я хотел бы выполнить в многопоточном режиме. Например, предположим, что я хочу просмотреть очень длинный список строк и выполнить некоторые базовые операции со строками для каждого элемента списка. Если я разделю список, отправлю каждый подсписок для обработки моим кодом цикла / строки в новом потоке и отправлю результаты обратно в очередь, будут ли эти рабочие нагрузки выполняться примерно одновременно? Самое главное, теоретически это ускорит время, необходимое для запуска скрипта?
Другой пример: я могу визуализировать и сохранить четыре разных изображения с помощью PIL в четырех разных потоках, и будет ли это быстрее, чем обработка изображений одно за другим? Думаю, именно этот компонент скорости меня действительно интересует, а не правильная терминология.
Я также знаю о модуле многопроцессорности, но сейчас меня больше всего интересуют задачи от малых до средних (10-30 секунд), поэтому я думаю, что многопоточность будет более подходящей, потому что подпроцессы могут запускаться медленно.
источник
Ответы:
GIL не препятствует нарезанию потоков. Все, что делает GIL, - это проверяет, что только один поток выполняет код Python за раз; управление по-прежнему переключается между потоками.
В этом случае GIL предотвращает использование более одного ядра ЦП или отдельных ЦП для параллельного выполнения потоков.
Это относится только к коду Python. Расширения C могут выпускать и выпускают GIL, позволяя нескольким потокам кода C и одному потоку Python работать на нескольких ядрах. Это распространяется на операции ввода-вывода, контролируемые ядром, такие как
select()
вызовы чтения и записи сокетов, благодаря чему Python обрабатывает сетевые события достаточно эффективно в многопоточной многоядерной настройке.То, что затем делают многие серверные развертывания, - это запуск нескольких процессов Python, чтобы операционная система могла выполнять планирование между процессами для максимального использования ядер вашего процессора. Вы также можете использовать
multiprocessing
библиотеку для обработки параллельной обработки нескольких процессов из одной кодовой базы и родительского процесса, если это соответствует вашим вариантам использования.Обратите внимание, что GIL применим только к реализации CPython; Jython и IronPython используют разные реализации потоков (собственные потоки времени выполнения Java VM и .NET соответственно).
Чтобы напрямую обратиться к вашему обновлению: любая задача, которая пытается повысить скорость за счет параллельного выполнения с использованием чистого кода Python, не увидит ускорения, поскольку многопоточный код Python привязан к одному потоку, выполняющемуся за раз. Однако, если вы смешиваете расширения C и операции ввода-вывода (например, операции PIL или numpy), и любой код C может работать параллельно с одним активным потоком Python.
Потоки Python отлично подходят для создания гибкого графического интерфейса или для обработки нескольких коротких веб-запросов, где ввод-вывод является более узким местом, чем код Python. Он не подходит для распараллеливания кода Python с интенсивными вычислениями, придерживаться
multiprocessing
модуля для таких задач или делегировать выделенную внешнюю библиотеку.источник
urllib.urlopen()
?), Вызов одного сценария Python из графического интерфейса Python и вызов нескольких операций PIL (напримерImage.transform()
) и numpy (напримерnumpy.array()
) с потоками. И вы привели еще несколько примеров в своем комментарии, таких как использование нескольких потоков для чтения файлов (напримерf.read()
?). Я знаю, что исчерпывающий список невозможен, просто хотел типы примеров, которые вы привели в своем обновлении. В любом случае, принял ваш ответ :)urllib.urlopen()
вызовет сетевые сокеты, ожидание ввода-вывода сокета - отличная возможность переключать потоки и делать что-то еще.Да. :)
У вас есть низкий уровень резьбы модуля и более высокий уровень многопоточности модуль. Но если вы просто хотите использовать многоядерные машины, многопроцессорность модуль - .
Цитата из документов :
источник
В Python разрешена многопоточность, единственная проблема заключается в том, что GIL будет следить за тем, чтобы одновременно выполнялся только один поток (без параллелизма).
Так что в основном, если вы хотите использовать многопоточность кода для ускорения вычислений, это не ускорит его, поскольку за раз выполняется только один поток, но если вы используете его, например, для взаимодействия с базой данных, он будет.
источник