現在、私は大量のWeb APIリクエストを作成中です。私はこのプロセスをasync
にしようとしましたが、妥当な時間内にこれを行うことができますが、接続を絞り込むことができないため、10
リクエスト/秒を送信しません。私は調整のためのセマフォを使用していますが、私はネストされたループを持っているので、この文脈でどのように動作するのか完全にはわかりません。ループで同時に非同期リクエストを抑制する
私は基本的にモデルのリストを取得しており、各モデルにはその中の日のリストがあります。私はモデルの中で毎日のリクエストをする必要があります。日数は、1
から約50
まで、99%
の間であればいつでも1
になるはずです。だからasync
それぞれのモデルには約3000
があるので、私はasync
が完了する必要がある複数の日がある場合の日にしたいと思います。私は10
リクエスト/秒以下で滞在する必要があるので、これを行う最善の方法は、操作全体でリクエスト制限を10に設定することだと思いました。チェーン全体に接続を制限するセマフォを置くことができる場所はありますか?
個々のリクエストごとに、2
個の異なるデータを2回要求する必要があり、このAPIは現在バッチ処理をサポートしていません。
私はC#に新しく、async
に非常に新しいとWebRequests/HttpClient
に非常に新しいので、任意の助けに感謝します。ここにすべての関連コードを追加しようとしました。他に何かが必要なら私に知らせてください。
public static async Task GetWeatherDataAsync(List<Model> models)
{
SemaphoreSlim semaphore = new SemaphoreSlim(10);
var taskList = new List<Task<ComparisonModel>>();
foreach (var x in models)
{
await semaphore.WaitAsync();
taskList.Add(CompDaysAsync(x));
}
try
{
await Task.WhenAll(taskList.ToArray());
}
catch (Exception e) { }
finally
{
semaphore.Release();
}
}
public static async Task<Models> CompDaysAsync(Model model)
{
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = new
Headers.AuthenticationHeaderValue("Token","xxxxxxxx");
httpClient.Timeout = TimeSpan.FromMinutes(5);
var taskList = new List<Task<Models.DateTemp>>();
foreach (var item in model.list)
{
taskList.Add(WeatherAPI.GetResponseForDayAsync(item,
httpClient, Latitude, Longitude));
}
httpClient.Dispose();
try
{
await Task.WhenAll(taskList.ToArray());
}
catch (Exception e) { }
return model;
}
public static async Task<DateTemp> GetResponseForDayAsync(DateTemp date, HttpClient httpClient, decimal? Latitude, decimal? Longitude)
{
var response = await httpClient.GetStreamAsync(request1);
StreamReader myStreamReader = new StreamReader(response);
string responseData = myStreamReader.ReadToEnd();
double[] data = new double[2];
if (responseData != "[[null, null]]")
{
data = Array.ConvertAll(responseData.Replace("[", "").Replace("]", "").Split(','), double.Parse);
}
else { data = null; };
double precipData = 0;
var response2 = await httpClient.GetStreamAsync(request2);
StreamReader myStreamReader2 = new StreamReader(response2);
string responseData2 = myStreamReader2.ReadToEnd();
if (responseData2 != null && responseData2 != "[null]" && responseData2 != "[0.0]")
{
precipData = double.Parse(responseData2.Replace("[", "").Replace("]", ""));
}
date.Precip = precipData;
if (data != null)
{
date.minTemp = data[0];
date.maxTemp = data[1];
}
return date;
}
私は単純に 'Parallel.ForEach'を使う前にこれをしました。 'ParallelOptions'を必要とするオーバーロードは' MaxDegreeOfParallelism'を設定しますが、最初に各モデルの日を 'Enumerable.SelectMany'で平坦化する必要があります。 – Biscuits
私のコレクションをSelectManyすれば、モデル自体と関係のない私のすべての日々の大きなリストが得られます。それが本質的に関係しているのか、それを確実にするために何か特別なことをする必要がありますか? – DevDevDev
親オブジェクトと要素の両方からの情報を新しいオブジェクトに投影する結果セレクタを指定できる 'SelectMany'のオーバーロードがあります。 'Linq'構文は、それを簡単にします。 「Parallel.ForEach」は、アクション(またはタスク)を非同期で実行し、各繰り返しで完了するように依頼できることを覚えておいてください。 – Biscuits