Thread.start() не делает функцию неблокирующей в Python

Вопрос или проблема

Мне нужна функция, которая будет запускаться в конце другой функции неблокирующим образом. Для этого я использую потоки (и ответ здесь: https://stackoverflow.com/a/6683797/4552286).

import threading

def checkValidQRCode(qrcode):
    url=""
    headers = {
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json"  # Указываем тип содержимого как JSON
    }
    response = requests.get(url, headers=headers)
    # Проверяем код состояния ответа
    if response.status_code == 200:
        # Парсинг JSON ответа
        json = response.json()
        print(json)

        if len(json) > 0:
            print("открыть дверь по проверке валидного QR-кода")
            if(json[0]["Static"]==False):     # нестатичный код, должен быть помечен как использованный
                # запускаем обновление доступа в отдельном потоке
                thread = threading.Thread(target=updateAccessCodeToSpent, args=(json[0]["Id"],))
                thread.start()
            return "unlock"

def updateAccessCodeToSpent(id):
    time.sleep(5)

while(True):
     if someCondition == True:
         checkValidQRCode("qrcode")
         print("это код сразу после checkValidQRCode() в цикле")

Я хочу, чтобы оператор print после триггера в цикле выполнялся сразу после завершения обработки запроса. Он ожидает 5 секунд перед печатью. Кроме того, я знаю, что это время связано с обновлением доступа, так как когда я закомментирую time.sleep, код после триггера выполняется немедленно.

Ответ или решение

Проблема, с которой вы столкнулись, заключается в том, что функция checkValidQRCode, несмотря на использование потоков, блокирует выполнение последующих строк кода в основном потоке до тех пор, пока не завершится запрос requests.get() и последующие операции. Давайте разберем, как правильно запустить функцию updateAccessCodeToSpent в неблокирующем режиме и вернуть управление в основной поток сразу после обработки QR-кода.

Вот исправленная версия вашего кода:

import threading
import requests
import time

def checkValidQRCode(qrcode):
    url = ""
    headers = {
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json"  # Укажите тип содержимого как JSON
    }

    response = requests.get(url, headers=headers)

    # Проверяем код состояния ответа
    if response.status_code == 200:
        # Парсим JSON-ответ
        json = response.json()
        print(json)

        if len(json) > 0:
            print("unlock door from check valid qr code")
            if json[0]["Static"] == False:  # Нестатичный код, следует отметить как использованный
                # Запускаем updateAccessCodeToSpent в отдельном потоке
                thread = threading.Thread(target=updateAccessCodeToSpent, args=(json[0]["Id"],))
                thread.start()  # Это не блокирует основной поток
            return "unlock"

def updateAccessCodeToSpent(id):
    time.sleep(5)
    print(f"Access code {id} marked as spent.")

while True:
    if someCondition == True:
        checkValidQRCode("qrcode")
        print("this is code right after checkValidQRCode() in the loop")

Основные изменения в коде:

  1. Использование аргументов для потоков: Ваша строка args=(json[0]["Id"]) была некорректной. Для передачи единственного аргумента в args необходимо упаковать его в кортеж, добавив запятую: args=(json[0]["Id"],).

  2. Блокировка в основном потоке: Ваш запрос requests.get() выполняется в основном потоке, и на этом этапе выполнение заблокировано до получения ответа. Чтобы добиться неблокирующего поведения, вы можете создать отдельный поток для выполнения этого запроса или воспользоваться асинхронным программированием, например, библиотекой asyncio и ее компонентами для работы с асинхронными HTTP-запросами, такими как aiohttp.

Пример с использованием threading:

Если вы хотите оставить текущую структуру кода, но позаботиться о том, чтобы HTTP-запросы также выполнялись в фоновом режиме, вы могли бы организовать его так:

def checkValidQRCode(qrcode):
    thread = threading.Thread(target=processQRCode, args=(qrcode,))
    thread.start()

def processQRCode(qrcode):
    url = ""
    headers = {
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json"
    }

    response = requests.get(url, headers=headers)

    if response.status_code == 200:
        json = response.json()
        print(json)

        if len(json) > 0:
            print("unlock door from check valid qr code")
            if json[0]["Static"] == False:
                threading.Thread(target=updateAccessCodeToSpent, args=(json[0]["Id"],)).start()
            return "unlock"

Используя этот подход, вы создаете отдельный поток для выполнения всей логики обработки QR-кода, так что основной поток не блокируется, даже если запрашивается HTTP-ресурс.

Заключение

В случае, если вы часто работаете с параллельными задачами или асинхронным кодом, вам может быть полезно рассмотреть использование более современных инструментов и библиотек, таких как asyncio, чтобы улучшить производительность и читабельность вашего кода.

Оцените материал
Добавить комментарий

Капча загружается...