При создании алгоритма в Python (интерпретируемый язык), который включал многопоточность, я был удивлен, увидев, что время выполнения было не лучше, чем по сравнению с последовательным алгоритмом, который я ранее построил. Чтобы понять причину этого результата, я немного прочитал и считаю, что то, что я узнал, предлагает интересный контекст для лучшего понимания различий между многопоточностью и многопроцессорностью.
Многоядерные системы могут осуществлять несколько потоков выполнения, поэтому Python должен поддерживать многопоточность. Но Python - это не скомпилированный язык, а интерпретируемый язык 1 . Это означает, что программа должна быть интерпретирована для запуска, и интерпретатор не знает о программе до того, как она начнет выполняться. Однако он знает правила Python, и затем он динамически применяет эти правила. Оптимизация в Python должна быть главным образом оптимизацией самого интерпретатора, а не кода, который должен быть запущен. Это отличается от скомпилированных языков, таких как C ++, и имеет последствия для многопоточности в Python. В частности, Python использует глобальную блокировку интерпретатора для управления многопоточностью.
С другой стороны, скомпилированный язык, ну, в общем, скомпилирован. Программа обрабатывается «полностью», где сначала она интерпретируется в соответствии с ее синтаксическими определениями, затем отображается в независимое от языка промежуточное представление и, наконец, связывается в исполняемый код. Этот процесс позволяет оптимизировать код, поскольку он доступен во время компиляции. Различные программные взаимодействия и отношения определяются во время создания исполняемого файла и принятия надежных решений по оптимизации.
В современных средах интерпретатор Python должен разрешать многопоточность, и это должно быть безопасным и эффективным. В этом и заключается разница между интерпретируемым языком и компилируемым языком. Интерпретатор не должен мешать внутреннему обмену данными из разных потоков, в то же время оптимизируя использование процессоров для вычислений.
Как отмечалось в предыдущих статьях, и процесс, и поток являются независимыми последовательными выполнениями, основное отличие состоит в том, что память распределяется между несколькими потоками процесса, а процессы изолируют свои области памяти.
В Python данные защищены от одновременного доступа разными потоками с помощью Global Interpreter Lock. Это требует, чтобы в любой программе Python в каждый момент времени мог выполняться только один поток. С другой стороны, можно запускать несколько процессов, поскольку память для каждого процесса изолирована от любого другого процесса, и процессы могут выполняться на нескольких ядрах.
1 У Дональда Кнута есть хорошее объяснение интерпретирующих процедур в «Искусстве компьютерного программирования: фундаментальные алгоритмы».