Задачи не порождают дополнительные потоки, поэтому вы сохраняете это снижение производительности, и они не блокируют вызывающий поток, поэтому я считаю, что это удовлетворит обе эти потребности.
string[] urls = GetUrls();
var requests = new Dictionary<string, Task<string>>()
var responses = new Dictionary<string, string>();
// send off each request and store the on-going task in a dictionary
foreach (string url in urls)
requests.Add(url, Task.Factory.StarNew(() => return WebClient.DownloadString(url))
// get the results asynchronously
Task.Factory.StartNew(() => {
foreach (var request in requests)
responses.Add(request.key, request.Result)
}
Теперь, когда вы получите ответ, вы можете сделать это несколькими способами. Выше будет получить результат каждой задачи по одному. Когда вы вызываете результат, он будет ждать завершения задачи, блокируя вызывающий метод, и на этом этапе выдает исключения, если задача не выполнена. Вы также можете подождать весь пакет сразу с помощью Task.WaitAll (); Поскольку вызов .Result блокирует вызывающий метод, вам также придется получать результаты из задачи.
В этом примере предполагается, что вы отправляете HTTP-GET и хотите получить результат в виде строки, но независимо от того, какой метод или результат вы хотите получить, способ выполнения вызова и получения результата будет одинаковым. Вы также хотите добавить обработку исключений, чтобы перехватывать любые исключения, которые могут быть выброшены. Вы можете ознакомиться с обработкой исключений задачи здесь .