import asyncio
async def access_resource(semaphore, resource_id):
async with semaphore:
print(f"Resource {resource_id} acquired.")
await asyncio.sleep(1) # Имитация работы с ресурсом
print(f"Resource {resource_id} released.")
async def main():
semaphore = asyncio.Semaphore(2) # Ограничиваем до 2 одновременных доступов
tasks = [access_resource(semaphore, i) for i in range(5)]
await asyncio.gather(*tasks)
if __name__ == "__main__":
asyncio.run(main())
asyncio.Semaphore()
- это примитив синхронизации в Python's asyncio
, который позволяет ограничивать количество одновременных сопрограмм (coroutines), имеющих доступ к общему ресурсу. Это своего рода счетчик, который инициализируется с определенным значением (количество разрешенных одновременных доступов).
Основной принцип работы:
acquire()
: Каждая сопрограмма, желающая получить доступ к ресурсу, должна вызвать метод acquire()
у семафора. Если счетчик семафора больше нуля, он уменьшается на единицу, и сопрограмма получает доступ. Если счетчик равен нулю, сопрограмма приостанавливается (переходит в состояние ожидания) до тех пор, пока другая сопрограмма не освободит семафор.release()
: Когда сопрограмма заканчивает работу с ресурсом, она вызывает метод release()
, который увеличивает счетчик семафора на единицу. Если есть ожидающие сопрограммы, одна из них (в произвольном порядке, если не указано иное) возобновляет выполнение.Пример использования:
import asyncio
import random
async def worker(semaphore, worker_id):
async with semaphore: # Эквивалентно: await semaphore.acquire(); try: ... finally: semaphore.release()
print(f"Worker {worker_id}: Получает доступ к ресурсу...")
# Имитация работы с ресурсом
await asyncio.sleep(random.uniform(0.5, 2))
print(f"Worker {worker_id}: Завершил работу с ресурсом.")
async def main():
# Ограничиваем количество одновременных рабочих до 3
semaphore = asyncio.Semaphore(3)
tasks = [worker(semaphore, i) for i in range(10)]
await asyncio.gather(*tasks)
if __name__ == "__main__":
asyncio.run(main())
Разъяснение примера:
semaphore
с начальным значением 3. Это означает, что только 3 сопрограммы могут одновременно находиться в критической секции (внутри контекстного менеджера async with semaphore
).worker
имитирует работу с общим ресурсом. Используется async with semaphore:
, что обеспечивает гарантированное освобождение семафора даже при возникновении исключений внутри блока кода. Это эквивалентно try...finally и позволяет избежать зависаний.main
создается 10 задач worker
.asyncio.gather(*tasks)
запускает все задачи параллельно.
Ключевые преимущества использования asyncio.Semaphore()
:
В заключение, asyncio.Semaphore()
- это мощный инструмент для синхронизации и контроля доступа к ресурсам в асинхронном коде Python. Он позволяет создавать потокобезопасные приложения, которые эффективно используют ресурсы и избегают проблем, связанных с параллельным доступом. Использование async with semaphore:
является предпочтительным способом, так как гарантирует освобождение семафора.