logo

Багатопотоковість в Python

У цій статті розглядаються основи багатопоточності в мові програмування Python. Так як багатопроцесорність , багатопотоковість — це спосіб досягнення багатозадачності. У багатопоточності поняття нитки використовується. Давайте спочатку розберемося з поняттям нитка в архітектурі комп'ютера.

Що таке процес у Python?

В обчислювальній техніці а процес це екземпляр комп’ютерної програми, яка виконується. Будь-який процес має 3 основні складові:



  • Виконувана програма.
  • Пов’язані дані, необхідні для програми (змінні, робоча область, буфери тощо)
  • Контекст виконання програми (Стан процесу)

Знайомство з потоками Python

А нитка це об’єкт у процесі, який можна запланувати для виконання. Крім того, це найменша одиниця обробки, яку можна виконати в ОС (операційній системі). Простими словами, потік — це послідовність таких інструкцій у програмі, яка може виконуватися незалежно від іншого коду. Для простоти ви можете припустити, що потік є просто підмножиною процесу! Потік містить всю цю інформацію в a Блок керування потоками (TCB) :

  • Ідентифікатор потоку: Кожному новому потоку присвоюється унікальний ідентифікатор (TID).
  • Покажчик стека: Вказує на стек потоку в процесі. Стек містить локальні змінні в межах потоку.
  • Лічильник програми: регістр, який зберігає адресу інструкції, яка в даний момент виконується потоком.
  • Стан потоку: може бути запущено, готово, очікує, розпочато або готово.
  • Набір реєстрів потоку: регістри, призначені потоку для обчислень.
  • Покажчик батьківського процесу: Покажчик на блок керування процесом (PCB) процесу, у якому живе потік.

Розгляньте діаграму нижче, щоб зрозуміти зв’язок між процесом і його потоком:

багатопотоковий-python-11

Зв'язок між процесом і його потоком



Кілька потоків можуть існувати в одному процесі, де:

  • Кожен потік містить своє набір реєстрів і локальні змінні (зберігаються в стеку) .
  • Усі потоки процесу мають спільний доступ глобальні змінні (зберігаються в купі) і програмний код .

Розгляньте діаграму нижче, щоб зрозуміти, як у пам’яті існує кілька потоків:

багатопотоковий-python-21

Наявність кількох потоків у пам'яті



Вступ до потоків у Python

Багатопотоковість визначається як здатність процесора виконувати декілька потоків одночасно. У простому одноядерному процесорі це досягається за допомогою частого перемикання між потоками. Це називається перемикання контексту . У контекстному перемиканні стан потоку зберігається, а стан іншого потоку завантажується щоразу, коли відбувається будь-яке переривання (через введення-виведення або встановлене вручну). Перемикання контексту відбувається настільки часто, що здається, що всі потоки працюють паралельно (це називається багатозадачність ).

Розглянемо схему нижче, на якій процес містить два активних потоки:

багатопотоковий-python-31

Багатопотоковість

Багатопотоковість в Python

в Python , різьблення модуль забезпечує дуже простий та інтуїтивно зрозумілий API для створення кількох потоків у програмі. Давайте спробуємо крок за кроком зрозуміти багатопотоковий код.

Крок 1: Модуль імпорту

Спочатку імпортуйте модуль потоків.

import threading>

Крок 2: Створити ланцюжок

Щоб створити новий потік, ми створюємо об’єкт Нитка клас. Він приймає «ціль» і «аргументи» як параметри. The мета це функція, яка виконується потоком, тоді як args є аргументи, які будуть передані цільовій функції.

t1 = threading.Thread(target, args) t2 = threading.Thread(target, args)>

крок 3: Почати гілку

Щоб почати потік, ми використовуємо початок() метод класу Thread.

t1.start() t2.start()>

крок 4: Закінчити потік Виконання

Після запуску потоків поточна програма (ви можете розглядати її як основний потік) також продовжує виконуватися. Щоб зупинити виконання поточної програми до завершення потоку, ми використовуємо приєднатися() метод.

t1.join() t2.join()>

У результаті поточна програма спочатку чекатиме завершення t1 і потім t2 . Після їх завершення виконуються інші оператори поточної програми.

приклад:

Розглянемо простий приклад використання потокового модуля.

Цей код демонструє, як використовувати модуль потоків Python для одночасного обчислення квадрата та куба числа. Дві нитки, t1> і t2> , створені для виконання цих розрахунків. Вони запускаються, і їх результати друкуються паралельно перед тим, як програма надрукує Готово! коли обидва потоки завершаться. Потоковість використовується для досягнення паралелізму та підвищення продуктивності програми під час виконання завдань, що містять інтенсивні обчислення.

Python3




import> threading> def> print_cube(num):> >print>(>'Cube: {}'> .>format>(num>*> num>*> num))> def> print_square(num):> >print>(>'Square: {}'> .>format>(num>*> num))> if> __name__>=>=>'__main__'>:> >t1>=> threading.Thread(target>=>print_square, args>=>(>10>,))> >t2>=> threading.Thread(target>=>print_cube, args>=>(>10>,))> >t1.start()> >t2.start()> >t1.join()> >t2.join()> >print>(>'Done!'>)>

>

>

Вихід:

Square: 100 Cube: 1000 Done!>

Розгляньте схему нижче, щоб краще зрозуміти, як працює вищевказана програма:

багатопотоковий-python-4

Багатопотоковість

приклад:

У цьому прикладі ми використовуємо os.getpid() функція для отримання ідентифікатора поточного процесу. Ми використовуємо threading.main_thread() функція для отримання об’єкта основного потоку. У нормальних умовах основний потік — це потік, з якого було запущено інтерпретатор Python. назва атрибут об'єкта потоку використовується для отримання імені потоку. Тоді ми використовуємо threading.current_thread() функція для отримання поточного об’єкта потоку.

Розглянемо наведену нижче програму Python, у якій ми друкуємо назву потоку та відповідний процес для кожного завдання.

Цей код демонструє, як використовувати модуль потокової обробки Python для одночасного виконання двох завдань. Основна програма ініціює два потоки, t1> і t2> , кожен з яких відповідає за виконання конкретного завдання. Потоки виконуються паралельно, а код надає інформацію про ідентифікатор процесу та імена потоків. Theos>модуль використовується для доступу до ідентифікатора процесу та ' threading'> Модуль використовується для керування потоками та їх виконанням.

Python3




import> threading> import> os> def> task1():> >print>(>'Task 1 assigned to thread: {}'>.>format>(threading.current_thread().name))> >print>(>'ID of process running task 1: {}'>.>format>(os.getpid()))> def> task2():> >print>(>'Task 2 assigned to thread: {}'>.>format>(threading.current_thread().name))> >print>(>'ID of process running task 2: {}'>.>format>(os.getpid()))> if> __name__>=>=> '__main__'>:> >print>(>'ID of process running main program: {}'>.>format>(os.getpid()))> >print>(>'Main thread name: {}'>.>format>(threading.current_thread().name))> >t1>=> threading.Thread(target>=>task1, name>=>'t1'>)> >t2>=> threading.Thread(target>=>task2, name>=>'t2'>)> >t1.start()> >t2.start()> >t1.join()> >t2.join()>

>

>

Вихід:

ID of process running main program: 1141 Main thread name: MainThread Task 1 assigned to thread: t1 ID of process running task 1: 1141 Task 2 assigned to thread: t2 ID of process running task 2: 1141>

Наведена нижче діаграма пояснює цю концепцію:

багатопотоковий-python-5

Багатопотоковість

Отже, це був короткий вступ до багатопоточності в Python. Наступна стаття цієї серії присвячена синхронізація між кількома потоками . Багатопотоковість у Python | Набір 2 (Синхронізація)

Python ThreadPool

Пул потоків — це набір потоків, які створюються заздалегідь і можуть повторно використовуватися для виконання кількох завдань. Модуль concurrent.futures у Python надає клас ThreadPoolExecutor, який спрощує створення та керування пулом потоків.

У цьому прикладі ми визначаємо робочу функцію, яка виконуватиметься в потоці. Ми створюємо ThreadPoolExecutor з максимум 2 робочими потоками. Потім ми надсилаємо два завдання до пулу за допомогою методу submit. Пул керує виконанням завдань у своїх робочих потоках. Ми використовуємо метод завершення роботи, щоб дочекатися завершення всіх завдань перед продовженням основного потоку.

Багатопотоковість може допомогти вам зробити ваші програми ефективнішими та оперативнішими. Однак важливо бути обережним під час роботи з потоками, щоб уникнути таких проблем, як умови перегонів і взаємоблокування.

Цей код використовує пул потоків, створений за допомогою concurrent.futures.ThreadPoolExecutor> для одночасного виконання двох робочих завдань. Основний потік очікує завершення використання робочих потоків pool.shutdown(wait=True)> . Це дозволяє ефективно паралельно обробляти завдання в багатопоточному середовищі.

Python3




import> concurrent.futures> def> worker():> >print>(>'Worker thread running'>)> pool>=> concurrent.futures.ThreadPoolExecutor(max_workers>=>2>)> pool.submit(worker)> pool.submit(worker)> pool.shutdown(wait>=>True>)> print>(>'Main thread continuing to run'>)>

>

>

k найближчий сусід
Вихід

Worker thread running Worker thread running Main thread continuing to run>