Вы должны использовать Microsoft Reactive Framework (также известную как Rx) - NuGet System.Reactive
и добавить using System.Reactive.Linq;
- тогда вы можете делать довольно интересные вещи.
Прежде всего, нам нужно исправить ваш код так, чтобывам не нужно полагаться на вызовы .Result
.
Давайте просто предположим, что ваш код выполняется в методе с именем Main
- тогда вы можете изменить свой код так, чтобы он работал следующим образом:
async void Main()
{
// ...
string BuildUrl(string summonerName) => $@"https://na1.api.riotgames.com/lol/summoner/v4/summoners/by-name/{summonerName}apikeyiswhatgoesintherestofthispartoftheapi";
foreach (var item in matchlistd)
{
var response2 = await client.GetAsync(BuildUrl(item.summonerName));
if (response2.IsSuccessStatusCode)
{
var content2 = await response2.Content.ReadAsStringAsync();
summonerName player = JsonConvert.DeserializeObject<summonerName>(content2);
accountinfo.Add(player);
}
}
// ...
}
Обратите внимание на async
и два ключевых слова await
.
Теперь давайте перепишем ваш цикл, чтобы он был наблюдаемым Rx.Наблюдаемый подобен перечислимому, но вместо непосредственного создания всех значений он создает значения по одному за раз.
IObservable<summonerName> query =
/* 1 */ from item in matchlistd.ToObservable()
/* 2 */ from response2 in Observable.FromAsync(() => client.GetAsync(BuildUrl(item.summonerName)))
/* 3 */ where response2.IsSuccessStatusCode
/* 4 */ from content2 in Observable.FromAsync(() => response2.Content.ReadAsStringAsync())
/* 5 */ select JsonConvert.DeserializeObject<summonerName>(content2);
- превращает ваше
matchlistd
перечисляемое в наблюдаемое - вызывает
client.GetAsync
и развертывает задачу, используя Observable.FromAsync
, чтобы создать наблюдаемый ответ на сообщение - отфильтровывает
response2.IsSuccessStatusCode == false
- вызывает
response2.Content.ReadAsStringAsync()
и развертывает задачу с помощьюObservable.FromAsync
для создания наблюдаемой string
- преобразует
string
в summonerName
.
Затем вы можете сделать это, чтобы получить все результаты и поместить их вВаш список:
accountinfo.AddRange(await query.ToList());
Теперь мы просто хотим, чтобы это производило только до 20 запросов в секунду.Вот модифицированный запрос:
IObservable<summonerName> query =
from items in matchlistd.ToObservable().Buffer(20).Zip(Observable.Timer(TimeSpan.Zero, TimeSpan.FromSeconds(1.0)), (x, t) => x)
from item in items
from response2 in Observable.FromAsync(() => client.GetAsync(BuildUrl(item.summonerName)))
where response2.IsSuccessStatusCode
from content2 in Observable.FromAsync(() => response2.Content.ReadAsStringAsync())
select JsonConvert.DeserializeObject<summonerName>(content2);
Обратите внимание на следующую часть:
from items in matchlistd.ToObservable().Buffer(20).Zip(Observable.Timer(TimeSpan.Zero, TimeSpan.FromSeconds(1.0)), (x, t) => x)
from item in items
Это секретный соус..Buffer(20)
& TimeSpan.FromSeconds(1.0)
- это биты, которые можно изменить для настройки поведения.