threading
— Thread-based parallelism¶
Вихідний код: Lib/threading.py
This module constructs higher-level threading interfaces on top of the lower
level _thread
module. See also the queue
module.
Змінено в версії 3.7: Раніше цей модуль був необов’язковим, тепер він доступний завжди.
Примітка
While they are not listed below, the camelCase
names used for some
methods and functions in this module in the Python 2.x series are still
supported by this module.
CPython implementation detail: У CPython, завдяки Global Interpreter Lock, лише один потік може виконувати код Python одночасно (навіть якщо певні бібліотеки, орієнтовані на продуктивність, можуть подолати це обмеження). Якщо ви хочете, щоб ваша програма краще використовувала обчислювальні ресурси багатоядерних машин, радимо використовувати multiprocessing
або concurrent.futures.ProcessPoolExecutor
. Однак потокова розв’язка все ще є відповідною моделлю, якщо ви хочете одночасно запускати кілька завдань, пов’язаних із вводом-виводом.
Цей модуль визначає такі функції:
-
threading.
active_count
()¶ Повертає кількість активних об’єктів
Thread
. Повернена кількість дорівнює довжині списку, повернутогоenumerate()
.
-
threading.
current_thread
()¶ Повертає поточний об’єкт
Thread
, що відповідає потоку керування абонента. Якщо потік керування викликаючого не було створено за допомогою модуляthreading
, повертається фіктивний об’єкт потоку з обмеженою функціональністю.
-
threading.
excepthook
(args, /)¶ Обробляти неперехоплений виняток, викликаний
Thread.run()
.Аргумент args має такі атрибути:
exc_type: Тип винятку.
exc_value: значення винятку, може бути
None
.exc_traceback: Зворотне відстеження винятків, може бути
None
.потік: Потік, який викликав виняток, може бути
None
.
Якщо exc_type дорівнює
SystemExit
, виняток мовчки ігнорується. В іншому випадку виняток друкується наsys.stderr
.Якщо ця функція викликає виняткову ситуацію, для її обробки викликається
sys.excepthook()
.threading.excepthook()
можна перевизначити, щоб контролювати, як обробляються неперехоплені винятки, викликаніThread.run()
.Зберігання exc_value за допомогою спеціального хука може створити еталонний цикл. Його слід явно очистити, щоб розірвати цикл посилання, коли виняток більше не потрібен.
Зберігання потоку за допомогою спеціального хука може відновити його, якщо він встановлений для об’єкта, який завершується. Уникайте зберігання thread після завершення власного хука, щоб уникнути відновлення об’єктів.
Дивись також
sys.excepthook()
обробляє неперехоплені винятки.Нове в версії 3.8.
-
threading.
get_ident
()¶ Повертає «ідентифікатор потоку» поточного потоку. Це ненульове ціле число. Його значення не має прямого значення; воно призначене як магічне печиво, яке можна використовувати, наприклад. щоб індексувати словник даних, що стосуються потоку. Ідентифікатори потоку можуть бути перероблені, коли потік завершується та створюється інший.
Нове в версії 3.3.
-
threading.
get_native_id
()¶ Повертає власний інтегральний ідентифікатор потоку поточного потоку, призначеного ядром. Це невід’ємне ціле число. Його значення може використовуватися для однозначної ідентифікації цього конкретного потоку в системі (до завершення роботи потоку, після чого значення може бути повторно використано ОС).
Availability: Windows, FreeBSD, Linux, macOS, OpenBSD, NetBSD, AIX.
Нове в версії 3.8.
-
threading.
enumerate
()¶ Повертає список усіх активних наразі об’єктів
Thread
. Список включає демонічні потоки та об’єкти-фіктивні потоки, створеніcurrent_thread()
. Він виключає завершені потоки та потоки, які ще не розпочато. Однак основний потік завжди є частиною результату, навіть якщо він завершується.
-
threading.
main_thread
()¶ Повертає головний об’єкт
Thread
. У нормальних умовах основний потік — це потік, з якого було запущено інтерпретатор Python.Нове в версії 3.4.
-
threading.
settrace
(func)¶ Встановити функцію трасування для всіх потоків, запущених з модуля
threading
. func буде передано доsys.settrace()
для кожного потоку перед викликом його методуrun()
.
-
threading.
setprofile
(func)¶ Встановіть функцію профілю для всіх потоків, запущених із модуля
threading
. func буде передано доsys.setprofile()
для кожного потоку перед викликом його методуrun()
.
-
threading.
stack_size
([size])¶ Повертає розмір стека потоків, який використовувався під час створення нових потоків. Необов’язковий аргумент size визначає розмір стека, який буде використовуватися для згодом створених потоків, і має дорівнювати 0 (використовувати платформу або налаштоване за замовчуванням) або додатне ціле значення принаймні 32 768 (32 КіБ). Якщо size не вказано, використовується 0. Якщо зміна розміру стека потоку не підтримується, виникає
RuntimeError
. Якщо вказаний розмір стека недійсний, виникає помилкаValueError
і розмір стека не змінюється. 32 КіБ наразі є мінімальним підтримуваним значенням розміру стеку, щоб гарантувати достатній простір стеку для самого інтерпретатора. Зауважте, що деякі платформи можуть мати певні обмеження щодо значень розміру стека, як-от вимагати мінімальний розмір стека > 32 КБ або вимагати виділення кратного розміру сторінки системної пам’яті – для отримання додаткової інформації слід звернутися до документації платформи (сторінки 4 КБ є поширеними; використання кратних 4096 для розміру стека є запропонованим підходом за відсутності більш конкретної інформації).Availability: Windows, systems with POSIX threads.
Цей модуль також визначає таку константу:
-
threading.
TIMEOUT_MAX
¶ Максимально допустиме значення для параметра timeout функцій блокування (
Lock.acquire()
,RLock.acquire()
,Condition.wait()
тощо). Якщо вказати час очікування, більший за це значення, виникнеOverflowError
.Нове в версії 3.2.
Цей модуль визначає ряд класів, які детально описані в розділах нижче.
Конструкція цього модуля базується на моделі потоків Java. Однак, коли Java робить блокування та змінні умови базовою поведінкою кожного об’єкта, у Python вони є окремими об’єктами. Клас Thread
Python підтримує підмножину поведінки класу Thread Java; на даний момент немає пріоритетів, немає груп потоків, і потоки не можна знищити, зупинити, призупинити, відновити або перервати. Статичні методи класу Thread Java, коли вони реалізовані, відображаються на функції рівня модуля.
Усі методи, описані нижче, виконуються атомарно.
Локальні дані потоку¶
Локальні дані потоку — це дані, значення яких залежать від потоку. Щоб керувати локальними даними потоку, просто створіть екземпляр local
(або підклас) і збережіть у ньому атрибути:
mydata = threading.local()
mydata.x = 1
Значення екземпляра будуть різними для окремих потоків.
-
class
threading.
local
¶ Клас, який представляє дані локального потоку.
For more details and extensive examples, see the documentation string of the
_threading_local
module.
Об’єкти потоку¶
The Thread
class represents an activity that is run in a separate
thread of control. There are two ways to specify the activity: by passing a
callable object to the constructor, or by overriding the run()
method in a subclass. No other methods (except for the constructor) should be
overridden in a subclass. In other words, only override the
__init__()
and run()
methods of this class.
Після створення об’єкта потоку його діяльність має бути запущена викликом методу потоку start()
. Це викликає метод run()
в окремому потоці керування.
Коли активність потоку розпочато, він вважається «живим». Він перестає бути живим, коли його метод run()
завершує роботу - або звичайним способом, або шляхом виклику необробленого винятку. Метод is_alive()
перевіряє, чи живий потік.
Інші потоки можуть викликати метод потоку join()
. Це блокує потік, що викликає, доки не буде завершено потік, чий метод join()
викликається.
Нитка має назву. Ім’я можна передати конструктору та прочитати або змінити за допомогою атрибута name
.
Якщо метод run()
викликає виняток, для його обробки викликається threading.excepthook()
. За замовчуванням threading.excepthook()
мовчки ігнорує SystemExit
.
Потік можна позначити як «потік демона». Значення цього прапорця полягає в тому, що вся програма Python завершує роботу, коли залишаються лише потоки демона. Початкове значення успадковується від потоку створення. Прапор можна встановити через властивість daemon
або аргумент конструктора daemon.
Примітка
Потоки демона раптово зупиняються під час завершення роботи. Їхні ресурси (такі як відкриті файли, транзакції бази даних тощо) можуть не вивільнятися належним чином. Якщо ви хочете, щоб ваші потоки зупинялися акуратно, зробіть їх недемонічними та використовуйте відповідний механізм сигналізації, такий як Event
.
Є об’єкт «основний потік»; це відповідає початковому потоку керування в програмі Python. Це не потік демона.
There is the possibility that «dummy thread objects» are created. These are
thread objects corresponding to «alien threads», which are threads of control
started outside the threading module, such as directly from C code. Dummy
thread objects have limited functionality; they are always considered alive and
daemonic, and cannot be join()
ed. They are never deleted,
since it is impossible to detect the termination of alien threads.
-
class
threading.
Thread
(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)¶ Цей конструктор слід завжди викликати з ключовими аргументами. Аргументами є:
group should be
None
; reserved for future extension when aThreadGroup
class is implemented.target — об’єкт, який викликається методом
run()
. За замовчуваннямNone
, тобто нічого не викликається.name is the thread name. By default, a unique name is constructed of the form «Thread-N» where N is a small decimal number.
args is the argument tuple for the target invocation. Defaults to
()
.kwargs — це словник ключових аргументів для цільового виклику. За замовчуванням
{}
.Якщо не
None
, daemon явно встановлює, чи є потік демонічним. ЯкщоNone
(за замовчуванням), демонічна властивість успадковується з поточного потоку.Якщо підклас перевизначає конструктор, він повинен обов’язково викликати конструктор базового класу (
Thread.__init__()
), перш ніж робити щось інше з потоком.Змінено в версії 3.3: Added the daemon argument.
-
start
()¶ Розпочати діяльність потоку.
Він має бути викликаний щонайбільше один раз на об’єкт потоку. Він організовує виклик методу
run()
об’єкта в окремому потоці керування.Цей метод викличе
RuntimeError
, якщо викликати кілька разів для того самого об’єкта потоку.
-
run
()¶ Метод, що представляє діяльність потоку.
Ви можете перевизначити цей метод у підкласі. Стандартний метод
run()
викликає викликаний об’єкт, який передається конструктору об’єкта як аргумент target, якщо такий є, з позиційними аргументами та ключовими аргументами, взятими з аргументів args і kwargs відповідно.
-
join
(timeout=None)¶ Зачекайте, поки потік завершиться. Це блокує потік, що викликає, доки потік, чий метод
join()
викликається, не завершиться (звичайно або через необроблений виняток), або доки не настане додатковий час очікування.When the timeout argument is present and not
None
, it should be a floating point number specifying a timeout for the operation in seconds (or fractions thereof). Asjoin()
always returnsNone
, you must callis_alive()
afterjoin()
to decide whether a timeout happened – if the thread is still alive, thejoin()
call timed out.Якщо аргумент timeout відсутній або
None
, операція буде заблокована до завершення потоку.A thread can be
join()
ed many times.join()
викликаєRuntimeError
, якщо робиться спроба приєднатися до поточного потоку, оскільки це призведе до взаємоблокування. Також є помилкоюjoin()
потоку до того, як він був запущений, і спроби зробити це викликають той самий виняток.
-
name
¶ Рядок, який використовується лише для ідентифікації. Він не має семантики. Декільком потокам можна присвоїти однакові назви. Початкове ім’я задається конструктором.
-
ident
¶ «Ідентифікатор потоку» цього потоку або «Немає», якщо потік не було запущено. Це ненульове ціле число. Перегляньте функцію
get_ident()
. Ідентифікатори потоку можуть бути перероблені, коли потік завершується та створюється інший. Ідентифікатор доступний навіть після завершення потоку.
-
native_id
¶ The native integral thread ID of this thread. This is a non-negative integer, or
None
if the thread has not been started. See theget_native_id()
function. This represents the Thread ID (TID
) as assigned to the thread by the OS (kernel). Its value may be used to uniquely identify this particular thread system-wide (until the thread terminates, after which the value may be recycled by the OS).Примітка
Подібно до ідентифікаторів процесів, ідентифікатори потоків дійсні (гарантовано унікальні для всієї системи) лише з моменту створення потоку до його завершення.
Availability: Requires
get_native_id()
function.Нове в версії 3.8.
-
is_alive
()¶ Повернути, чи живий потік.
Цей метод повертає
True
безпосередньо перед запуском методуrun()
до завершення роботи методуrun()
. Функція модуляenumerate()
повертає список усіх активних потоків.
-
daemon
¶ A boolean value indicating whether this thread is a daemon thread (True) or not (False). This must be set before
start()
is called, otherwiseRuntimeError
is raised. Its initial value is inherited from the creating thread; the main thread is not a daemon thread and therefore all threads created in the main thread default todaemon
=False
.Уся програма Python завершує роботу, якщо не залишиться активних потоків, які не є демонами.
-
Блокування об’єктів¶
Примітивне блокування — це примітив синхронізації, який не належить певному потоку, коли він заблокований. У Python наразі це найнижчий доступний примітив синхронізації рівня, реалізований безпосередньо модулем розширення _thread
.
Примітивний замок знаходиться в одному з двох станів: «заблоковано» або «розблоковано». Створюється в розблокованому стані. Він має два основні методи: acquire()
і release()
. Коли стан розблоковано, acquire()
змінює стан на заблокований і повертає негайно. Коли стан заблоковано, acquire()
блокується, доки виклик release()
в іншому потоці не змінить його на розблокований, після чого виклик acquire()
скидається він блокується та повертається. Метод release()
слід викликати лише в заблокованому стані; він змінює стан на розблокований і негайно повертається. Якщо буде зроблена спроба зняти розблоковане блокування, буде викликано RuntimeError
.
Блокування також підтримують протокол управління контекстом.
Якщо в acquire()
заблоковано більше одного потоку, який очікує, поки стан стане розблокованим, лише один потік продовжує роботу, коли виклик release()
скидає стан до розблокованого; який із потоків, що очікують, продовжується, не визначено та може відрізнятися в різних реалізаціях.
Усі методи виконуються атомарно.
-
class
threading.
Lock
¶ Клас, що реалізує примітивні об’єкти блокування. Після того, як потік отримав блокування, наступні спроби отримати його блокуються, доки він не буде звільнений; будь-який потік може його звільнити.
Note that
Lock
is actually a factory function which returns an instance of the most efficient version of the concrete Lock class that is supported by the platform.-
acquire
(blocking=True, timeout=-1)¶ Отримайте блокування, блокування або неблокування.
При виклику з аргументом blocking, встановленим на
True
(за замовчуванням), блокувати, доки блокування не буде розблоковано, потім установіть його на locked і повернітьTrue
.При виклику з аргументом blocking, встановленим на
False
, не блокувати. Якщо виклик із блокуванням, встановленим наTrue
, заблокує, негайно повернітьFalse
; інакше встановіть блокування на locked і повернітьTrue
.When invoked with the floating-point timeout argument set to a positive value, block for at most the number of seconds specified by timeout and as long as the lock cannot be acquired. A timeout argument of
-1
specifies an unbounded wait. It is forbidden to specify a timeout when blocking is false.Поверненим значенням є
True
, якщо блокування отримано успішно,False
, якщо ні (наприклад, якщо минув тайм-аут).Змінено в версії 3.2: Параметр timeout є новим.
Змінено в версії 3.2: Отримання блокування тепер може бути перервано сигналами на POSIX, якщо це підтримує базова реалізація потоків.
-
release
()¶ Відпустіть блокування. Це можна викликати з будь-якого потоку, а не лише з потоку, який отримав блокування.
Коли замок заблоковано, скиньте його до розблокованого та поверніться. Якщо будь-які інші потоки заблоковано в очікуванні розблокування блокування, дозвольте рівно одному з них продовжити.
Під час виклику для розблокованого блокування виникає
RuntimeError
.Поверненого значення немає.
-
locked
()¶ Return true if the lock is acquired.
-
Об’єкти RLock¶
Блокування повторного входу — це примітив синхронізації, який може бути отриманий кілька разів одним потоком. Внутрішньо він використовує поняття «володіння потоком» і «рівень рекурсії» на додаток до заблокованого/розблокованого стану, який використовується примітивними блокуваннями. У заблокованому стані деякий потік володіє блокуванням; у розблокованому стані жоден потік не володіє ним.
To lock the lock, a thread calls its acquire()
method; this
returns once the thread owns the lock. To unlock the lock, a thread calls
its release()
method. acquire()
/release()
call pairs may be nested; only the final release()
(the
release()
of the outermost pair) resets the lock to unlocked and
allows another thread blocked in acquire()
to proceed.
Reentrant locks also support the context management protocol.
-
class
threading.
RLock
¶ Цей клас реалізує об’єкти повторного входу. Блокування повторного входу має бути звільнено потоком, який його отримав. Як тільки потік отримав блокування повторного входу, той самий потік може отримати його знову без блокування; потік повинен звільнити його один раз за кожен раз, коли він його отримав.
Зауважте, що
RLock
насправді є фабричною функцією, яка повертає екземпляр найефективнішої версії конкретного класу RLock, який підтримується платформою.-
acquire
(blocking=True, timeout=-1)¶ Отримайте блокування, блокування або неблокування.
When invoked without arguments: if this thread already owns the lock, increment the recursion level by one, and return immediately. Otherwise, if another thread owns the lock, block until the lock is unlocked. Once the lock is unlocked (not owned by any thread), then grab ownership, set the recursion level to one, and return. If more than one thread is blocked waiting until the lock is unlocked, only one at a time will be able to grab ownership of the lock. There is no return value in this case.
When invoked with the blocking argument set to true, do the same thing as when called without arguments, and return
True
.When invoked with the blocking argument set to false, do not block. If a call without an argument would block, return
False
immediately; otherwise, do the same thing as when called without arguments, and returnTrue
.When invoked with the floating-point timeout argument set to a positive value, block for at most the number of seconds specified by timeout and as long as the lock cannot be acquired. Return
True
if the lock has been acquired, false if the timeout has elapsed.Змінено в версії 3.2: Параметр timeout є новим.
-
release
()¶ Зніміть блокування, зменшивши рівень рекурсії. Якщо після декремента він дорівнює нулю, скиньте блокування до розблокованого (не належить жодному потоку), і якщо будь-які інші потоки заблоковані в очікуванні розблокування блокування, дозвольте рівно одному з них продовжити. Якщо після декременту рівень рекурсії все ще ненульовий, блокування залишається заблокованим і належить потоку, що викликає.
Only call this method when the calling thread owns the lock. A
RuntimeError
is raised if this method is called when the lock is unlocked.Поверненого значення немає.
-
Об’єкти стану¶
Змінна умови завжди асоціюється з якимось блокуванням; це можна передати, або він буде створений за замовчуванням. Передача одного корисна, коли кілька змінних умови повинні використовувати один і той же блокування. Блокування є частиною об’єкта умови: вам не потрібно відстежувати його окремо.
Змінна умови підпорядковується протоколу керування контекстом: використання оператора with
отримує пов’язане блокування протягом тривалості включеного блоку. Методи acquire()
і release()
також викликають відповідні методи пов’язаного блокування.
Інші методи повинні викликатися з відповідним блокуванням. Метод wait()
знімає блокування, а потім блокує, доки інший потік не розбудить його, викликавши notify()
або notify_all()
. Після пробудження wait()
знову отримує блокування та повертається. Також можна вказати тайм-аут.
Метод notify()
активує один із потоків, які очікують на змінну умови, якщо такі очікують. Метод notify_all()
активує всі потоки, які очікують на змінну умови.
Примітка: методи notify()
і notify_all()
не знімають блокування; це означає, що активований потік або потоки не повернеться зі свого виклику wait()
негайно, а лише тоді, коли потік, який викликав notify()
або notify_all()
остаточно відмовляється від власності на замок.
Типовий стиль програмування з використанням умовних змінних використовує блокування для синхронізації доступу до деякого спільного стану; потоки, які зацікавлені в певній зміні стану, викликають wait()
неодноразово, доки не побачать бажаний стан, тоді як потоки, які змінюють стан, викликають notify()
або notify_all()
, коли вони змінюють стан таким чином, що це може бути бажаним станом для одного з офіціантів. Наприклад, наступний код є загальною ситуацією виробник-споживач з необмеженою ємністю буфера:
# Consume one item
with cv:
while not an_item_is_available():
cv.wait()
get_an_available_item()
# Produce one item
with cv:
make_an_item_available()
cv.notify()
Цикл while
для перевірки умови програми необхідний, оскільки wait()
може повернутися через довільний тривалий час, а умова, яка спонукала до виклику notify()
, може не довше зберігаються. Це властиво багатопоточному програмуванню. Метод wait_for()
можна використовувати для автоматизації перевірки умов і полегшує обчислення тайм-аутів:
# Consume an item
with cv:
cv.wait_for(an_item_is_available)
get_an_available_item()
Щоб вибрати між notify()
і notify_all()
, подумайте, чи одна зміна стану може бути цікавою лише для одного чи кількох потоків, що очікують. наприклад у типовій ситуації виробник-споживач додавання одного елемента до буфера потребує лише пробудження одного потоку споживача.
-
class
threading.
Condition
(lock=None)¶ Цей клас реалізує об’єкти умовної змінної. Змінна умови дозволяє одному або декільком потокам чекати, поки вони не будуть сповіщені іншим потоком.
Якщо вказано аргумент lock, а не
None
, це має бути об’єктLock
абоRLock
, і він використовується як основний блокування. В іншому випадку створюється новий об’єктRLock
, який використовується як основний блокування.Змінено в версії 3.3: змінено з функції фабрики на клас.
-
acquire
(*args)¶ Отримайте основний замок. Цей метод викликає відповідний метод основного блокування; значення, що повертається, є тим, що повертає цей метод.
-
release
()¶ Звільніть базовий замок. Цей метод викликає відповідний метод основного блокування; немає зворотного значення.
-
wait
(timeout=None)¶ Зачекайте, поки не буде сповіщено або поки не настане час очікування. Якщо потік, що викликає, не отримав блокування під час виклику цього методу, виникає
RuntimeError
.Цей метод знімає основне блокування, а потім блокує, доки його не розбудить виклик
notify()
абоnotify_all()
для тієї самої змінної умови в іншому потоці, або доки не настане додатковий тайм-аут. Після пробудження або вичерпання часу блокування знову блокується та повертається.When the timeout argument is present and not
None
, it should be a floating point number specifying a timeout for the operation in seconds (or fractions thereof).Якщо основним блокуванням є
RLock
, він не звільняється за допомогою свого методуrelease()
, оскільки це може не розблокувати блокування, якщо його було отримано кілька разів рекурсивно. Замість цього використовується внутрішній інтерфейс класуRLock
, який справді розблоковує його, навіть якщо він був рекурсивно отриманий кілька разів. Інший внутрішній інтерфейс потім використовується для відновлення рівня рекурсії, коли блокування знову отримано.Поверненим значенням є
True
, якщо не минув заданий тайм-аут, у такому випадку воно має значенняFalse
.Змінено в версії 3.2: Раніше метод завжди повертав
None
.
-
wait_for
(predicate, timeout=None)¶ Зачекайте, поки умова оціниться як істинна. предикат має бути викликаним, результат якого буде інтерпретуватися як логічне значення. Може бути надано тайм-аут, що дає максимальний час очікування.
Цей допоміжний метод може викликати
wait()
неодноразово, доки предикат не буде задоволено або поки не настане час очікування. Значення, що повертається, є останнім значенням, що повертається предикатом, і оцінюється якFalse
, якщо час очікування методу минув.Ігноруючи функцію тайм-ауту, виклик цього методу приблизно еквівалентний написанню:
while not predicate(): cv.wait()
Таким чином, застосовуються ті самі правила, що й для
wait()
: блокування має бути утримано під час виклику та повторно отримане після повернення. Предикат обчислюється з утриманим блокуванням.Нове в версії 3.2.
-
notify
(n=1)¶ За замовчуванням активувати один потік, який очікує за цієї умови, якщо такий є. Якщо потік, що викликає, не отримав блокування під час виклику цього методу, виникає
RuntimeError
.Цей метод активує щонайбільше n потоків, які очікують змінної умови; це безопераційний режим, якщо немає потоків, що очікують.
Поточна реалізація активує рівно n потоків, якщо принаймні n потоків очікують. Однак покладатися на таку поведінку небезпечно. Майбутня оптимізована реалізація може час від часу запускати більше ніж n потоків.
Примітка: пробуджений потік фактично не повертається після свого виклику
wait()
, доки він не зможе повторно отримати блокування. Оскількиnotify()
не знімає блокування, його виклик повинен це зробити.
-
notify_all
()¶ Розбудити всі потоки, що очікують за цією умовою. Цей метод діє як
notify()
, але активує всі потоки, що очікують, а не один. Якщо потік, що викликає, не отримав блокування під час виклику цього методу, виникаєRuntimeError
.
-
Об’єкти семафора¶
Це один із найстаріших примітивів синхронізації в історії інформатики, винайдений першим голландським комп’ютерним науковцем Едсгером В. Дейкстрою (він використовував імена P()
і V()
замість acquire()
і release()
).
Семафор керує внутрішнім лічильником, який зменшується при кожному виклику acquire()
і збільшується при кожному виклику release()
. Лічильник ніколи не може опускатися нижче нуля; коли acquire()
виявляє, що він дорівнює нулю, він блокується, чекаючи, поки інший потік викличе release()
.
Семафори також підтримують протокол управління контекстом.
-
class
threading.
Semaphore
(value=1)¶ Цей клас реалізує семафорні об’єкти. Семафор керує атомарним лічильником, який представляє кількість викликів
release()
мінус кількість викликівacquire()
плюс початкове значення. Методacquire()
блокує, якщо необхідно, доки не зможе повернутися, не зробивши лічильник негативним. Якщо не вказано, значення за замовчуванням дорівнює 1.Необов’язковий аргумент дає початкове значення для внутрішнього лічильника; за замовчуванням
1
. Якщо задане значення менше 0, виникаєValueError
.Змінено в версії 3.3: змінено з функції фабрики на клас.
-
acquire
(blocking=True, timeout=None)¶ Придбайте семафор.
При виклику без аргументів:
Якщо внутрішній лічильник більше нуля під час входу, зменште його на одиницю та негайно поверніть
True
.Якщо внутрішній лічильник дорівнює нулю під час входу, блокуйте, доки не пробудите виклик
release()
. Після пробудження (і лічильник більше 0), зменшіть лічильник на 1 і повернітьTrue
. Кожен викликrelease()
пробуджуватиме рівно один потік. Не слід покладатися на порядок, у якому пробуджуються потоки.
When invoked with blocking set to false, do not block. If a call without an argument would block, return
False
immediately; otherwise, do the same thing as when called without arguments, and returnTrue
.При виклику з timeout, відмінним від
None
, він блокуватиметься щонайбільше на timeout секунд. Якщо отримання не завершується успішно протягом цього інтервалу, повертаєтьсяFalse
. В іншому випадку повернітьTrue
.Змінено в версії 3.2: Параметр timeout є новим.
-
release
(n=1)¶ Відпустіть семафор, збільшивши внутрішній лічильник на n. Коли він був нульовим під час входу, а інші потоки чекають, коли він знову стане більшим за нуль, розбудіть n з цих потоків.
Змінено в версії 3.9: Додано параметр n, щоб одночасно звільнити кілька потоків, що очікують.
-
-
class
threading.
BoundedSemaphore
(value=1)¶ Клас, що реалізує обмежені семафорні об’єкти. Обмежений семафор перевіряє, чи його поточне значення не перевищує початкове значення. Якщо це так, виникає
ValueError
. У більшості ситуацій семафори використовуються для захисту ресурсів з обмеженою ємністю. Якщо семафор запускається занадто багато разів, це ознака помилки. Якщо не вказано, значення за замовчуванням дорівнює 1.Змінено в версії 3.3: змінено з функції фабрики на клас.
Semaphore
Приклад¶
Семафори часто використовуються для захисту ресурсів з обмеженою потужністю, наприклад, сервера бази даних. У будь-якій ситуації, коли розмір ресурсу фіксований, ви повинні використовувати обмежений семафор. Перед створенням будь-яких робочих потоків ваш головний потік ініціалізує семафор:
maxconnections = 5
# ...
pool_sema = BoundedSemaphore(value=maxconnections)
Після створення робочі потоки викликають методи отримання та випуску семафора, коли їм потрібно підключитися до сервера:
with pool_sema:
conn = connectdb()
try:
# ... use connection ...
finally:
conn.close()
Використання обмеженого семафора зменшує ймовірність того, що програмна помилка, через яку семафор буде звільнено більше, ніж отримано, залишиться непоміченою.
Об’єкти подій¶
Це один із найпростіших механізмів зв’язку між потоками: один потік сигналізує про подію, а інші потоки чекають її.
Об’єкт події керує внутрішнім прапором, який можна встановити на true за допомогою методу set()
і скинути на false за допомогою методу clear()
. Метод wait()
блокує, доки прапор не стане істинним.
-
class
threading.
Event
¶ Клас, що реалізує об’єкти подій. Подія керує прапором, який можна встановити на true за допомогою методу
set()
і скинути на false за допомогою методуclear()
. Методwait()
блокує, доки прапор не стане істинним. Прапор спочатку фальшивий.Змінено в версії 3.3: змінено з функції фабрики на клас.
-
is_set
()¶ Повертає
True
тоді і тільки тоді, коли внутрішній прапор має значення true.
-
set
()¶ Встановіть для внутрішнього прапора значення true. Усі нитки, які чекають, коли це стане правдою, пробуджуються. Потоки, які викликають
wait()
, коли прапор встановлено як true, взагалі не блокуватимуться.
-
clear
()¶ Скиньте внутрішній прапор на false. Згодом потоки, що викликають
wait()
, блокуватимуться, доки не буде викликаноset()
, щоб знову встановити внутрішній прапор на true.
-
wait
(timeout=None)¶ Block until the internal flag is true. If the internal flag is true on entry, return immediately. Otherwise, block until another thread calls
set()
to set the flag to true, or until the optional timeout occurs.When the timeout argument is present and not
None
, it should be a floating point number specifying a timeout for the operation in seconds (or fractions thereof).This method returns
True
if and only if the internal flag has been set to true, either before the wait call or after the wait starts, so it will always returnTrue
except if a timeout is given and the operation times out.Змінено в версії 3.1: Раніше метод завжди повертав
None
.
-
Об’єкти таймера¶
Цей клас представляє дію, яку слід запускати лише після того, як мине певний час — таймер. Timer
є підкласом Thread
і як такий також функціонує як приклад створення власних потоків.
Timers are started, as with threads, by calling their start()
method. The timer can be stopped (before its action has begun) by calling the
cancel()
method. The interval the timer will wait before
executing its action may not be exactly the same as the interval specified by
the user.
Наприклад:
def hello():
print("hello, world")
t = Timer(30.0, hello)
t.start() # after 30 seconds, "hello, world" will be printed
-
class
threading.
Timer
(interval, function, args=None, kwargs=None)¶ Створіть таймер, який запускатиме функцію з аргументами args і аргументами ключового слова kwargs після закінчення інтервалу секунд. Якщо args має значення
None
(за замовчуванням), тоді використовуватиметься порожній список. Якщо kwargs має значенняNone
(за замовчуванням), тоді використовуватиметься порожній dict.Змінено в версії 3.3: змінено з функції фабрики на клас.
-
cancel
()¶ Зупиніть таймер і скасуйте виконання дії таймера. Це спрацює, лише якщо таймер все ще перебуває в стадії очікування.
-
Загороджувальні об’єкти¶
Нове в версії 3.2.
Цей клас забезпечує простий примітив синхронізації для використання фіксованою кількістю потоків, які повинні чекати один одного. Кожен із потоків намагається подолати бар’єр, викликаючи метод wait()
і блокуватиметься, доки всі потоки не виконають свої виклики wait()
. У цей момент потоки звільняються одночасно.
Бар’єр можна повторно використовувати будь-яку кількість разів для однакової кількості потоків.
Як приклад, ось простий спосіб синхронізації потоку клієнта та сервера:
b = Barrier(2, timeout=5)
def server():
start_server()
b.wait()
while True:
connection = accept_connection()
process_server_connection(connection)
def client():
b.wait()
while True:
connection = make_connection()
process_client_connection(connection)
-
class
threading.
Barrier
(parties, action=None, timeout=None)¶ Створіть бар’єрний об’єкт для сторон кількості потоків. Action, якщо надається, є викликом, який викликається одним із потоків, коли вони звільняються. timeout — це значення часу очікування за замовчуванням, якщо для методу
wait()
його не вказано.-
wait
(timeout=None)¶ Пройти шлагбаум. Коли всі потоки, які є стороною бар’єру, викличуть цю функцію, усі вони звільняються одночасно. Якщо надається тайм-аут, він використовується замість будь-якого, який було надано конструктору класу.
Повернене значення є цілим числом у діапазоні від 0 до parties – 1, різне для кожного потоку. Це можна використати для вибору потоку для виконання деяких спеціальних завдань, наприклад:
i = barrier.wait() if i == 0: # Only one thread needs to print this print("passed the barrier")
Якщо дія була надана конструктору, один із потоків викликатиме її до того, як буде звільнено. Якщо цей виклик викликає помилку, шлагбаум переходить у несправний стан.
Якщо виклик закінчився, шлагбаум переходить у несправний стан.
Цей метод може викликати виключення
BrokenBarrierError
, якщо бар’єр зламано або скинуто під час очікування потоку.
-
reset
()¶ Поверніть бар’єр до стандартного порожнього стану. Будь-які потоки, які очікують на нього, отримають виняток
BrokenBarrierError
.Зауважте, що використання цієї функції може потребувати певної зовнішньої синхронізації, якщо існують інші потоки, стан яких невідомий. Якщо бар’єр зламано, можливо, краще залишити його та створити новий.
-
abort
()¶ Переведіть шлагбаум в зламаний стан. Це призводить до того, що будь-які активні або майбутні виклики
wait()
завершуються помилкою зBrokenBarrierError
. Використовуйте це, наприклад, якщо один із потоків потрібно перервати, щоб уникнути блокування програми.Можливо, буде краще просто створити бар’єр із розумним значенням timeout, щоб автоматично захистити один із потоків від збою.
-
parties
¶ Кількість потоків, необхідних для проходження бар’єру.
-
n_waiting
¶ Кількість потоків, які зараз очікують у бар’єрі.
-
broken
¶ Логічне значення, яке має значення
True
, якщо бар’єр знаходиться в зламаному стані.
-
-
exception
threading.
BrokenBarrierError
¶ Цей виняток, підклас
RuntimeError
, виникає, коли об’єктBarrier
скидається або зламано.
Використання блокувань, умов і семафорів у операторі with
¶
All of the objects provided by this module that have acquire()
and
release()
methods can be used as context managers for a with
statement. The acquire()
method will be called when the block is
entered, and release()
will be called when the block is exited. Hence,
the following snippet:
with some_lock:
# do something...
еквівалентно:
some_lock.acquire()
try:
# do something...
finally:
some_lock.release()
Наразі об’єкти Lock
, RLock
, Condition
, Semaphore
і BoundedSemaphore
можна використовувати як контекст оператора with
менеджери.