Повестка дня

  • Цикл событий
  • Создание цикла событий с помощью Asyncio
  • Запись в файл с помощью Aiofiles и asyncio

Что такое цикл событий?

В программировании, основанном на событиях, цикл событий — это механизм, который позволяет программе ожидать и отправлять события или сообщения эффективным и оперативным образом. Цикл событий управляет порядком обработки событий и гарантирует своевременную реакцию программы на события.

Цикл событий в Python

В Python цикл событий часто реализуется с помощью модуля asyncio, который предоставляет инфраструктуру для написания асинхронного кода. Asyncio использует сопрограммы, функции, которые можно приостанавливать и возобновлять, для представления задач, которые могут выполняться одновременно. Цикл событий работает непрерывно, проверяя события и планируя выполнение задач по мере необходимости.

Когда происходит событие, такое как пользовательский ввод или сетевое соединение, цикл событий сигнализирует соответствующей задаче о возобновлении выполнения. Затем задача может обработать событие и создать новые события или задачи. Это позволяет программе одновременно реагировать на несколько событий, не блокируя и не ожидая завершения каждого события перед обработкой следующего.

Цикл событий в Python с Asyncio

Вот пример использования asyncio в Python для реализации простого веб-сервера, который прослушивает HTTP-запросы и отвечает сообщением. Создайте новый файл event_loop.py и вставьте следующий код:

import asyncio

async def handle_request(reader, writer):
    request = (await reader.read()).decode('utf-8')
    print("Handling request")
    print(request)
    
    headers = (
        b'HTTP/1.1 200 OK\r\n'
        b'Content-Type: text/plain\r\n'
        b'Access-Control-Allow-Origin: *\r\n'
        b'Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS\r\n'
        b'Access-Control-Allow-Headers: Content-Type\r\n\r\n'
    )

    response = b'Hello, world!'
    writer.write(headers + response)
    await writer.drain()
    writer.close()
    print("Request processed")

async def main():
    server = await asyncio.start_server(handle_request, 'localhost', 8000)
    print(f'Server running on {server.sockets[0].getsockname()}')
    async with server:
        await server.serve_forever()

loop = asyncio.get_event_loop()
try:
    loop.run_until_complete(main())
finally:
    loop.close()

Функция async def handle_request(reader, writer) является обработчиком запросов. Он получает два параметра: reader и writer. reader — это объект StreamReader, который считывает входящие данные от клиента, а writer — это объект StreamWriter, который записывает данные обратно клиенту.

Функция считывает входящий запрос от клиента с помощью reader.read(), который возвращает сопрограмму, которая считывает до 64 КБ данных от клиента. Затем он декодирует данные, используя decode('utf-8'), чтобы преобразовать их из байтов в строку.

После печати запроса функция формирует заголовок и тело ответа HTTP и отправляет их обратно клиенту с помощью метода writer.write(). Затем вызывается метод drain() для передачи данных клиенту, а метод writer.close() вызывается для закрытия соединения.

Функция async def main() — это основная сопрограмма, запускающая сервер с помощью asyncio.start_server(). Затем он выводит на консоль сообщение о том, что сервер работает, а затем входит в бесконечный цикл, используя server.serve_forever() для ожидания входящих клиентских запросов.

Затем цикл событий извлекается с использованием asyncio.get_event_loop(), а основная сопрограмма выполняется с использованием loop.run_until_complete(). Наконец, цикл событий закрывается с помощью loop.close(). Запустите файл с помощью:

python3 event_loop.py

Чтение и письмо — Asyncio-Ex-2

Вот еще один пример использования asyncio и цикла обработки событий для выполнения асинхронных операций ввода-вывода, таких как чтение и запись в файл.

Установите aiofiles и библиотеки asyncio python:

pip install aiofiles asyncio

Создайте файл example.txt в корневой папке. Создайте новый файл event_loop_file_writer.py в том же каталоге и введите следующий код:

import asyncio
import aiofiles

# Define an async function to write data to a file
async def write_to_file(filename, data):
    # Open the file for writing using async with, which ensures the file is closed
    # when we're done with it
    async with aiofiles.open(filename, 'w') as f:
        # Write the data to the file using the await keyword
        await f.write(data)

# Define an async function to read data from a file
async def read_from_file(filename):
    # Open the file for reading using async with, which ensures the file is closed
    # when we're done with it
    async with aiofiles.open(filename, 'r') as f:
        # Read the contents of the file using the await keyword
        data = await f.read()
        # Return the data as a string
        return data

# Define the main coroutine, which will run when we execute the script
async def main():
    # Set up a filename and some data to write to the file
    filename = 'example.txt'
    data = 'Hello, world!'

    # Create tasks to write and read the file concurrently
    write_task = asyncio.create_task(write_to_file(filename, data))
    read_task = asyncio.create_task(read_from_file(filename))

    # Wait for both tasks to complete
    await asyncio.gather(write_task, read_task)

    # Print the contents of the file to the console
    print(read_task.result())

# Run the main coroutine using asyncio.run, which creates and manages the event loop
if __name__ == '__main__':
    asyncio.run(main())

Этот код определяет три асинхронные функции: write_to_file, read_from_file и main.

write_to_file принимает два аргумента: filename и data. Он использует библиотеку aiofiles, чтобы открыть файл в режиме записи и записать данные в файл, используя await f.write(data).

read_from_file принимает один аргумент filename. Он открывает файл в режиме чтения, используя библиотеку aiofiles, считывает содержимое файла, используя await f.read(), и возвращает данные в виде строки.

main устанавливает имя файла и некоторые данные для записи в файл. Затем он создает две задачи для одновременной записи и чтения файла с использованием asyncio.create_task(). Он ожидает завершения обеих задач с помощью asyncio.gather() и, наконец, выводит содержимое файла на консоль.

Сценарий запускает сопрограмму main, используя asyncio.run(), которая создает цикл обработки событий и управляет им. Когда скрипт выполняется напрямую, он запускает сопрограмму main. Запустите этот файл с помощью:

python3 event_loop_file_writer.py

Если исходный текстовый файл — example.txt, проверьте его еще раз после запуска кода. вы сможете увидеть обновленный файл.

Где находится цикл обработки событий в приведенном выше примере кода?

Функция asyncio.run() создает цикл обработки событий, запускает переданную ей сопрограмму, а затем закрывает цикл обработки событий после завершения сопрограммы. Это позволяет легко управлять циклом обработки событий и упрощает асинхронное программирование.

Весь код приведенного выше примера доступен здесь, на Github:



Заключение

В заключение, цикл событий — это механизм, который позволяет программе ожидать и отправлять события или сообщения эффективно и оперативно. В Python модуль asyncio предоставляет инфраструктуру для написания асинхронного кода с использованием сопрограмм. Asyncio позволяет программам реагировать на несколько событий одновременно, не блокируя и не ожидая завершения каждого события перед обработкой следующего. В этой статье мы рассмотрели, как создать цикл событий с помощью asyncio и как использовать его для написания простого веб-сервера, который прослушивает HTTP-запросы и отвечает сообщением. Мы также изучили, как использовать asyncio и цикл событий для выполнения асинхронных операций ввода-вывода, таких как чтение и запись в файл. На этих примерах вы можете увидеть, насколько мощным может быть asyncio при написании эффективных и отзывчивых программ.

Это все для этой статьи! Не стесняйтесь оставлять отзывы или вопросы в комментариях. Если вы нашли это захватывающим чтением, хлопайте в ладоши и подписывайтесь! Ваше здоровье!