Есть ли какой-нибудь простой способ асинхронно выполнять число запросов Python? - PullRequest
3 голосов
/ 04 ноября 2019

Существует API localhost:8000/api/postdatetime/, который отвечает за изменение онлайн-статуса драйвера. Каждый раз, когда драйвер подключается к API и если ответ отправляется обратно, статус драйвера будет онлайн, в противном случае статус драйвера будет отключен.

Drivers need to give the response within every 10 seconds. Если от водителя нет ответа, он / она автоматически помечается как отключенный.

В настоящее время я получаю все зарегистрированные драйверы и запускаю вышеупомянутый API по одному драйверу за раз.

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

Код моего подхода описан ниже:

online-offline.py

import requests
import random
import math
from rest_framework.authtoken.models import Token

from ** import get_logged_in_driver_ids
from ** import Driver


def post_date_time():
    url = 'localhost:8000/api/postdatetime/'

    while True:
        # getting all logged in driver ids 
        logged_in_driver_ids = get_logged_in_driver_ids() 

        # filtering the driver who are logged in and storing their user id in the driver_query variable
        driver_query = Driver.objects.only('id', 'user_id').filter(id__in=logged_in_driver_ids).values('user_id')

        # storing the user id of driver in list
        driver_user_ids = [driver['user_id'] for driver in driver_query]

        # getting number of drivers who are supposed to hit the API
        drivers_subset_count = math.ceil(len(driver_user_ids)*(random.randint(75, 85)/100))

        # shuffle the driver ids list to randomize the driver id order
        random.shuffle(driver_user_ids)

        # getting the driver list of length drivers_subset_count
        required_drivers = driver_user_ids[:drivers_subset_count]

        for driver in required_drivers:
            token = Token.objects.only('key', 'user_id').get(user_id=driver)
            req_headers = {
                'Content-Type': 'application/json',
                'Accept': 'application/json',
                'Authorization': 'Token' + ' ' + str(token)
            }
            response = requests.post(url=url, headers=req_headers)
            print(response.text)



if __name == '__main__':
    post_date_time()

Есть ли идея, что я могу отправить запрос API localhost:8000/api/postdatetime/ в асинхронном режиме и обработать около 2-3000 драйверов в течение 10 секунд?

Я действительно новичок в реализации асинхронных кодов. Я прочитал несколько статей о библиотеке aiohttp, но во время ее реализации запутался.

Этот online-offline.py будет работать в течение всего времени моделирования.

Любая помощьбыть высоко оценен. Спасибо :)

1 Ответ

1 голос
/ 05 ноября 2019

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

  • использовать специальный синтаксис (async def, await - читать здесь для подробной информации)
  • делать запросы неспособ блокировки (чтобы их можно было ожидать)
  • использование asyncio.gather () аналогичного способа параллельного выполнения нескольких запросов "
  • начало цикла событий

Хотя возможно заставить requests библиотеку работать с asyncio с использованием потоков, проще и лучше использовать уже асинцио-совместимую библиотеку, такую ​​как aiohttp.

Takeвзгляните на фрагменты кода здесь *: они содержат примеры выполнения нескольких одновременных запросов. Перепишите ваш код таким же образом, это будет выглядеть так:

import asyncio


async def driver_request(driver):
    # ...
    # use aiohttp to make request with custom headers:
    # https://docs.aiohttp.org/en/stable/client_advanced.html#custom-request-headers


async def post_date_time():
    # ...

    await asyncio.gather(*[
        driver_request(driver) 
        for driver 
        in required_drivers
    ])


asyncio.run(post_date_time())

Локально вы выиграли 'По умолчанию не видно никакого эффекта, поэтому для его локального тестирования необходимо localhost отправить ответ с задержкой, чтобы эмулировать реальную сетевую задержку.


* В последней версии Python цикл обработки событий можетзапускаться только с asyncio.run ()

...