#vba #loops
#vba #циклы
Вопрос:
Я делаю кучу вызовов API на веб-сайт, который ограничивает количество вызовов API в час. Поскольку я иногда совершаю более 100 тыс. вызовов, иногда для получения всех необходимых мне данных требуются часы. Я хочу создать цикл, который проверяет, превышает ли количество вызовов API максимальное число в час, и если я превысил, проверьте разницу во времени между тем, когда я начал, и сейчас. Что-то вроде
startTime = Now()
For i = 1 To 150000
If counter <= 36000 Then
url = baseURL Str(i) "?apikey=" apiKey
resp.Open "GET", url
resp.Send
' Process the response
counter = counter 1
Else # More than 36,000 API calls have been made
Do
# Nothing in the loop, just waiting for 60 minutes to pass
While DateDiff(n, startTime, Now()) < 60
startTime = Now()
i = i - 1 # Need to re-loop on the current i
End If
Next i
У меня еще не было возможности протестировать его, но на бумаге похоже, что это сработает, но также выглядит как халтура (особенно если i = i — 1). Есть ли лучший способ сделать то, что я пытаюсь сделать?
Ответ №1:
Обновление: как указал Коминтерн, я пропустил счетчик I.
Каждый раз, когда счетчик достигает отметки 36000, я бы проверил, прошел ли час. Если бы этого не произошло, я бы сбросил время начала и продолжил, иначе я бы запланировал повторный запуск макроса через 1 час после времени начала.
Sub MakeAPICalls(Optional Counter As Long = 150000)
Dim Start: Start = Timer
Dim count As Long
For I = Counter To 150000
count = count 1
URL = baseURL Str(I) "?apikey=" apiKey
resp.Open "GET", URL
resp.Send
' Process the response
' Exit Do if complete
If (count Mod 36000) = 0 Then
If (Timer - Start) < 3600 Then
Start = Timer
Else
Application.OnTime Now (3600 - (Timer - Start)), "MakeAPICalls " amp; I
Exit Sub
End If
End If
Next
End Sub
Комментарии:
1. Нравится
OnTime
вызов, но он неcount
должен быть статическим?2. Счетчик и таймер могут быть сброшены, потому что вспомогательный модуль не будет вызываться снова, пока не истечет час. Часть, которая может потребоваться статической, — это код операционной системы. Я не могу сказать, когда он собрал все данные. Оператору придется структурировать свой код таким образом, чтобы многократное выполнение макроса все равно давало желаемый результат.
3. Имеет смысл. OP
Str([loopcounter])
встроен в URL. Я просто подумал, что было бы проще повторноcount
использовать .4. @Comintern Спасибо. Как я это пропустил!! Пожалуйста, ознакомьтесь с моим обновленным ответом.
5. Что заняло так много времени? Вы получили мой 1 почти час назад !! .. ЛОЛ, я просто хотел убедиться, что я ничего не пропустил.
Ответ №2:
Я бы упростил это, используя 2 вложенных цикла. Выполните внешний цикл по вашему количеству запросов, затем используйте внутренний цикл для выполнения ваших 36 тыс. запросов:
Dim requests As Long
For i = 1 To 150000 Step 36000
If i > 144000 Then requests = 5999 Else requests = 35999
For x = 0 To requests
URL = baseURL Str(i x) "?apikey=" apiKey
resp.Open "GET", URL
resp.Send
' Process the response
Next
Sleep 3600000 '1 hour
Next
Обратите внимание, что при этом используется Sleep
вызов API:
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Это гарантирует, что ваш процессор не будет загружен на 100% в течение часа в цикле бездействия. Если вы хотите, чтобы Excel оставался отзывчивым ( Sleep
буквально приостанавливает поток, в котором он выполняется), вы можете поместить a DoEvents
в свой цикл NOP, но это все равно будет потрачено впустую. тонны циклов процессора.
Комментарии:
1. Хорошо, я пропустил чтение вашего последнего утверждения. Я думаю, это
Sleep 1000:DoEvents
был бы хороший компромисс.Sleep 3600000
вероятно, следует скорректировать с учетом времени, необходимого для получения 36 тыс. вызовов (если для обработки 36 тыс. вызовов требуется 59 минут, макрос должен приостановиться на 1 минуту).