Трябва да направя множество уеб заявки, където URI са в DataTable. По-рано имах кода по-долу. Но разбрах, че това прави синхронни извиквания, тъй като await би изчакал GET/POST извикването да завърши и отговорът да бъде обработен, след което да продължи към следващата итерация.
foreach (DataRow dr in dt.Rows)
{
activeTasks.Add(SendRequestAsync(dr));
Task.WhenAll(activeTasks).Wait();
}
private async Task<string> SendRequestAsync(DataRow dr)
{
using (var client = new HttpClient())
{
string reqMethod = (dr["RequestMethod"] != null && dr["RequestMethod"].ToString() != "") ? dr["RequestMethod"].ToString() : "GET";
client.BaseAddress = new Uri(dr["URL"].ToString());
client.DefaultRequestHeaders.Accept.Clear();
string reqContentType = (dr["RequestContentType"] != null && dr["RequestContentType"].ToString() != "") ? dr["RequestContentType"].ToString() : "text/xml";
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(reqContentType));
HttpResponseMessage response = null;
try
{
if (reqMethod == "GET")
response = await client.GetAsync(client.BaseAddress.AbsoluteUri);
else
response = await client.PostAsync(client.BaseAddress.AbsoluteUri, null);
response.EnsureSuccessStatusCode();
var responseText = await response.Content.ReadAsStringAsync();
return responseText;
}
catch (Exception e)
{
return "-1";
}
}
}
След това попаднах на функцията Parallel и вместо това използвах Parallel.ForEach. Като този:
Parallel.ForEach(rows, dr =>
{
activeTasks.Add(SendRequestAsync(dr));
Task.WhenAll(activeTasks).Wait();
});
Това работи добре, постига се паралелизъм, заявките са асинхронни и завършва за част от времето в сравнение с по-ранното решение. Но проблемът е, че не е надежден - понякога получавам грешки като
- System.IndexOutOfRangeException: Индексът беше извън границите на масива
- System.InvalidOperationException: Колекцията е променена; операцията по изброяване може да не се изпълни.
Можем ли все пак да постигнем http async извиквания в рамките на foreach?
Parallel.ForEach
за това. Наистина просто искате да преместите свояTask.WhenAll
извън цикъла, в който добавяте задачи към списъка си със задачи. - person Jonathon Chase   schedule 22.10.2019