Взгляните на статический WaitHandle.WaitAll (WaitHandle [] waitHandles) метод.На этой странице есть отличный пример кода.
Как правило, любой класс, реализующий асинхронный шаблон, будет определять методы в форме:
IAsyncResult BeginXXX(AsyncCallback callback, Object state);
Result EndXXX(IAsyncResult asyncResult);
Вызов BeginXXX
вызывает метод асинхронно и вызываетEndXXX
заставляет текущий поток ждать завершения асинхронного метода.
Чтобы сделать несколько асинхронных вызовов, все, что вам нужно сделать, это вызвать BeginXXX
столько раз, сколько необходимо, а затем вызвать WaitHandle.WaitAll(...)
, передаваяв IAsyncResult.AsyncWaitHandle для всех вызовов, которые вы хотите ждать.
Чтобы ответить на второй вопрос, да, вы можете использовать GetAsynComplete
рекурсивно.Параметр state
, передаваемый вызову BeginXXX
, используется для идентификации запроса и доступен через свойство IAsyncResult.UserState
, так что вы можете сопоставить запрос с ответом.
Является ли это хорошей вещью, немного более субъективно.Обычно асинхронные вызовы проходят через пул потоков, поэтому их одновременное создание может исчерпать доступные потоки, и после этого новые вызовы помещаются в очередь до тех пор, пока поток не станет доступным.Существуют некоторые издержки при переключении между потоками, но это, вероятно, не будет значительным (если у вас не очень большое количество потоков) по сравнению со временем, затрачиваемым на это синхронно.