Próbuję wykonać make as many HTTP requests to a URL as possible, as quickly as possible.Jak określić równoczesne wąskie gardło żądania HTTP w .NET?
Używam tego kodu, aby umożliwić mi ograniczenie maksymalnych stopni równoległości, więc nie przepełniam pamięci przez jednoczesne odradzanie się wielu partycji o łącznej wartości Tasks
.
public static Task ForEachAsync<T>(this IEnumerable<T> source, int dop, Func<T, Task> body)
{
return Task.WhenAll(
from partition in Partitioner.Create(source).GetPartitions(dop)
select Task.Run(async delegate {
using (partition)
while (partition.MoveNext())
await body(partition.Current);
}));
}
Wygląda na to, że działa dobrze.
body()
zasadniczo sprowadza się do:
async Task Body()
{
var r = WebRequest.Create("// the url");
await r.GetResponseAsync();
}
Jednak wydaje się, że wąskie gardło gdzieś. Gdyby spróbować i zrobić 2500
iteracji, z różnym wartości dla dop
uzyskać te wyniki:
DOP: 50
Total Time: 00:00:14.4801781
Average (ms): 246.6088
StDev: 84.1327983759009
DOP: 75
Total Time: 00:00:09.8089530
Average (ms): 265.758
StDev: 110.22912244956
DOP: 100
Total Time: 00:00:11.9899793
Average (ms): 344.9168
StDev: 173.281468939295
DOP: 200
Total Time: 00:00:09.1512825
Average (ms): 627.0492
StDev: 572.616238312676
DOP: 500
Total Time: 00:00:09.3556978
Average (ms): 1361.5328
StDev: 1798.70589239157
DOP: 750
Total Time: 00:00:12.6076035
Average (ms): 2009.058
Normal Total: 5022646
StDev: 2348.20874093199
DOP: 1000
Total Time: 00:00:11.4721195
Average (ms): 2453.782
StDev: 2481.56238190299
DOP: 2000
Total: 00:00:11.6039888
Average (ms): 4100.5536
StDev: 2459.36983911063
które zdają się sugerować, że dop=50
jest mniejsza niż wąskie gardło. Kiedy jednak uzyskasz wartość powyżej dop~=100
, zauważysz, że czas każdego żądania wynosi Average
(średnia z tego, ile czasu zajmuje Func<T, Task> body
, aby uruchomić 2500
razy) rośnie prawie liniowo z DOP
(w tych wynikach jest nieco szumu, ale są one powtarzalne z małym błędem).
Sugeruje to, że istnieje "kolejka" wewnątrz pracy body
, prawda?
mam już zachodziło
ServicePointManager.DefaultConnectionLimit = int.MaxValue;
i jeśli mogę zrobić
servicePoint = ServicePointManager.FindServicePoint("// the url", null);
i monitorować
servicePoint.CurrentConnections
na każdej realizacji body
, jego zawsze równa dop
(z wyjątkiem początkowe podniesienie i oderwanie).
Próbowałem tego z różnych sieci, więc jest to mało prawdopodobne, aby był oparty na sprzęcie, i nie powinien być serwerem zdalnym, ponieważ jest przeznaczony do dużych obciążeń wejściowych (nie, że liczby, o których mówię są nawet ciężkie)
Jak mogę lepiej profilować to, co robię?
Istnieje wiele możliwości, ale domyślam się, że trafiasz w limit jednoczesnych połączeń w systemie Windows.Inną możliwością jest to, że sprzęt serwera traktuje połączenia jako potencjalny atak DOS i dławienie ich. –
Śr. Co? Na żądanie lub łącznie? Opublikuj kod pomiarowy. – usr
@usr Średni czas wykonania 'body' 2500 razy, źle wyjaśnij pytanie –