Оптимизация скорости кода Python, который тестирует результаты API - PullRequest
0 голосов
/ 19 сентября 2018

Я пытаюсь протестировать общедоступную веб-страницу, которая принимает запрос GET и возвращает другой файл JSON в зависимости от аргумента GET.

API выглядит как

https://www.example.com/api/page?type=check&code=[Insert string here]

Я сделал программу для проверки результатов всех возможных 4-буквенных строк в этом API.Мой код выглядит примерно так (с заменой фактического URL):

import time, urllib.request

for a in "ABCDEFGHIJKLMNOPQRSTUVWXYZ":
    for b in "ABCDEFGHIJKLMNOPQRSTUVWXYZ":
        for c in "ABCDEFGHIJKLMNOPQRSTUVWXYZ":
            for d in "ABCDEFGHIJKLMNOPQRSTUVWXYZ":
                a,b,c,d = "J","A","K","E"
                test = urllib.request.urlopen("https://www.example.com/api/page?type=check&code=" + a + b + c + d).read()
                if test != b'{"result":null}':
                    print(a + b + c + d)
                    f = open("codes", "a")
                    f.write(a + b + c + d + ",")
                    f.close()

Этот код полностью функционален и работает, как и ожидалось.Тем не менее, есть проблема.Поскольку программа не может прогрессировать, пока не получит ответы, этот метод очень медленный.Если это время проверки связи составляет 100 мс для API, то для каждой проверки потребуется 100 мс.Когда я изменил этот код, чтобы он мог тестировать половину результатов в одном экземпляре и половину в другом, я заметил, что скорость удвоилась.

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

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

Я пытался использовать многопоточность, но я не уверен, что это уместно или полезно.

1 Ответ

0 голосов
/ 19 сентября 2018

Пользовательский рабочий пул, как описано здесь: https://docs.python.org/3.7/library/multiprocessing.html

from multiprocessing import Pool

def test_url(code):
    ''' insert code to test URL '''
    pass

if __name__ == '__main__':
    with Pool(5) as p:
        print(p.map(test_url, [code1,code2,code3]))

Просто имейте в виду, что веб-сайт может ограничивать количество запросов, которые вы делаете.

КомуЕсли быть более конкретным с вашим примером, я бы разбил его на две фазы: (1) генерировать тестовые коды (2) тестовый URL, учитывая один тестовый код .Получив список сгенерированных кодов, вы можете применить вышеуказанную стратегию применения верификатора к каждому сгенерированному коду, используя рабочий пул.

Чтобы сгенерировать тестовые коды, вы можете использовать itertools:

codes_to_test = [''.join(i) for i in itertools.product(string.ascii_lowercase, repeat = 5)]

Вы лучше понимаете, как тестировать URL с одним тестовым кодом, поэтому я предполагаю, что вы можете написать функцию test_url(test_code), которая сделает соответствующий запрос URL и при необходимости проверит результат.Затем вы можете позвонить:

with Pool(5) as p:
    print(p.map(test_url, test_codes))

Кроме того, я бы предложил две вещи: сначала убедитесь, что test_codes не является огромным (например, взяв подсписок этих сгенерированных кодов), чтобы убедиться, чтоваш код работает правильно и (2) вы можете играть с размером рабочего пула, чтобы не перегружать вашу машину или API.

В качестве альтернативы вы можете использовать asyncio (https://docs.python.org/3/library/asyncio.html), чтобы сохранить всев одном процессе.

...