Документація на Python 3.7
Я також хотів би виділити наступну цитату з документації Pythonthreading
:
Деталі реалізації CPython: У CPython, завдяки глобальному блоку інтерпретаторів, лише один потік може виконувати код Python одночасно (навіть якщо певні бібліотеки, орієнтовані на ефективність, можуть подолати це обмеження). Якщо ви хочете, щоб ваша програма краще використовувала обчислювальні ресурси багатоядерних машин, вам рекомендується використовувати multiprocessing
або concurrent.futures.ProcessPoolExecutor
. Однак нарізка різьби все ще є відповідною моделлю, якщо ви хочете виконувати кілька завдань, пов'язаних з входом / виводом одночасно.
Це посилання на запис Глосарію, вglobal interpreter lock
якому пояснюється, що GIL означає, що потоковий паралелізм у Python не підходить для завдань, пов'язаних з процесором :
Механізм, що використовується інтерпретатором CPython, щоб переконатися, що лише один потік виконує байт-код Python одночасно. Це спрощує реалізацію CPython, роблячи об'єктну модель (включаючи критичні вбудовані типи, такі як dict), неявно захищеними від паралельного доступу. Блокування всього перекладача полегшує багатотрубну перекладач за рахунок більшої частини паралелізму, який надають багатопроцесорні машини.
Однак деякі модулі розширення, стандартні або сторонні, розроблені так, щоб звільнити GIL при виконанні обчислювально-інтенсивних завдань, таких як стиснення або хешування. Крім того, GIL завжди вивільняється при виконанні вводу / виводу.
Минулі зусилля по створенню інтерпретатора «з вільною ниткою» (той, який фіксує спільні дані на значно більш детальну деталізацію) не мали успіху, оскільки продуктивність постраждала в загальному випадку з одним процесором. Вважається, що подолання цього питання ефективності зробить реалізацію значно складнішою, а отже, і дорогішою у підтримці.
Ця цитата також передбачає, що дикти та таким чином присвоєння змінних також є безпечними для потоків як деталі реалізації CPython:
Далі, документи для multiprocessing
пакета пояснюють, як він долає GIL шляхом нерестування під час викриття інтерфейсу, аналогічного інтерфейсу threading
:
багатопроцесорна робота - це пакет, який підтримує нерестові процеси, використовуючи API, подібний модулю нарізки. Багатопроцесорний пакет пропонує як локальну, так і віддалену одночасність, ефективно наступаючи на глобальний блокнот інтерпретатора, використовуючи підпроцеси замість ниток. Завдяки цьому багатопроцесорний модуль дозволяє програмісту повністю використовувати декілька процесорів на даній машині. Він працює як на Unix, так і на Windows.
І документи дляconcurrent.futures.ProcessPoolExecutor
пояснення, що він використовується multiprocessing
як бекенд:
Клас ProcessPoolExecutor - це підклас Executor, який використовує пул процесів для асинхронного виконання викликів. ProcessPoolExecutor використовує мультипроцесорний модуль, що дозволяє йому здійснювати бічний крок глобального блоку інтерпретаторів, але також означає, що виконувати та повертати можна лише об'єкти, що вибираються.
що має протиставлятися іншому базовому класу, ThreadPoolExecutor
який використовує потоки замість процесів
ThreadPoolExecutor - це підклас Executor, який використовує пул потоків для асинхронного виконання викликів.
з якого ми робимо висновок, що ThreadPoolExecutor
він підходить лише для завдань, пов'язаних з входом / виводом, а ProcessPoolExecutor
також може обробляти завдання, пов'язані з процесором.
Наступне запитання задає питання, чому GIL існує в першу чергу: Чому блокування глобального перекладача?
Експерименти з процесами та потоками
У програмі Multiprocessing vs Threading Python я провів експериментальний аналіз процесу проти потоків у Python.
Швидкий попередній перегляд результатів: