Вот один из способов сделать это асинхронно, когда каждый раз, когда вы вызываете getExchangeAvailability (), он делает это в отдельном потоке, а затем ожидает завершения всех потоков, прежде чем вернуть окончательный список.
public List<AvailabilityList> _asyncGetResortsForDate(String month, int year)
{
List<RegionList> regions = this.getRegionLists();
List<AvailabilityList> availability = new List<AvailabilityList>();
List<WaitHandle> handles = new List<WaitHandle>();
List<AvailabilityList> _asyncResults = new List<AvailabilityList>();
regions.ForEach(parent =>
{
parent.Regions.ForEach(child =>
{
if (!String.Equals(child.ID, "?"))
{
int countryID = Int32.Parse(parent.CountryID);
Func<AvailabilityList> _getList = () =>
this.getExchangeAvailability(countryID, month, year, child.ID);
IAsyncResult res = _getList.BeginInvoke(new AsyncCallback(
x =>
{
AvailabilityList result =
(x.AsyncState as Func<AvailabilityList>).EndInvoke(x);
_asyncResults.Add(result);
}), _getList);
handles.Add(res.AsyncWaitHandle);
}
});
});
WaitHandle.WaitAll(handles.ToArray());
return _asyncResults;
}
Имейте в виду, однако, что если число итераций превышает 64, а максимальное число одновременных потоков по умолчанию (с использованием BeginInvoke ()) равно 64, то после этого момента вы не будете обрабатывать что-либо асинхронно до тех пор, пока один из 64 уже запущенные темы становятся свободными. Также могут быть или не быть некоторые издержки при переключении контекста между потоками. Одна вещь, которую вы, возможно, захотите проверить, это то, сколько времени занимает каждый вызов API, чтобы увидеть, действительно ли это того стоит.
РЕДАКТИРОВАТЬ - Что касается ошибки ограничения 64 потока, я бы предложил две вещи,
1) Вы должны сгруппировать асинхронные вызовы так, чтобы только каждый «родитель» выполнялся в своем собственном потоке, а не каждый дочерний элемент. Это должно уменьшить количество потоков, что-то вроде:
public List<AvailabilityList> _getAllChildren(RegionList parent, string month, int year)
{
List<AvailabilityList> list = new List<AvailabilityList>();
parent.Regions.ForEach(child =>
{
if (!String.Equals(child.ID, "?"))
{
int countryID = Int32.Parse(parent.CountryID);
AvailabilityList result = this.getExchangeAvailability(countryID, month, year, child.ID);
list.Add(result);
}
});
return list;
}
public List<AvailabilityList> _asyncGetResortsForDate(String month, int year)
{
List<RegionList> regions = this.getRegionLists();
List<AvailabilityList> availability = new List<AvailabilityList>();
List<WaitHandle> handles = new List<WaitHandle>();
List<AvailabilityList> _asyncResults = new List<AvailabilityList>();
regions.ForEach(parent =>
{
Func<List<AvailabilityList>> allChildren = () => _getAllChildren(parent, month, year);
IAsyncResult res = allChildren.BeginInvoke(new AsyncCallback(
x =>
{
List<AvailabilityList> result =
(x.AsyncState as Func<List<AvailabilityList>>).EndInvoke(x);
_asyncResults.AddRange(result);
}), allChildren);
handles.Add(res.AsyncWaitHandle);
});
WaitHandle.WaitAll(handles.ToArray());
return _asyncResults;
}
2) Вам может потребоваться добавить проверку перед добавлением в список WaitHandles, чтобы проверить, не рискуете ли вы превысить 64 потока:
var asyncHandle = res.AsyncWaitHandle;
if (handles.Count >= 64)
asyncHandle.WaitOne(); // wait for this one now
else if (handles.Count < 64)
handles.Add(asyncHandle);