835
Конструкции.пользовательского.режима
Cons
ole.WriteLine("returned {0:N0} bytes.", result);
}
}
break;
}
}
}
Этот код непосредственно не задействует
Interlocked
-методы, так как весь ко-
ординирующий код инкапсулирован в класс
AsyncCoordinator
. Я подробнее опишу
его ниже, а
пока расскажу, что этот класс делает. В процессе конструирования класс
MultiWebRequest
инициализирует класс
AsyncCoordinator
и словарь с набором
URI серверов (и их будущих результатов). Затем он асинхронно выполняет все
веб-запросы.
Сначала вызывается метод
AboutToBegin
класса
AsyncCoordinator
,
которому передается количество запланированных запросов
1
. Затем происходит
инициирование запроса вызовом метода
GetByteArrayAsync
класса
HttpClient
.
Метод возвращает объект
Task
,
для которого я вызываю
ContinueWith
, чтобы при
получении ответа сервера полученные байты параллельно обрабатывались методом
ComputeResult
во многих потоках пула. После завершения всех запросов к веб-
серверам вызывается метод
AllBegun
класса
AsyncCoordinator
,
которому передается
имя метода, который следует запустить после выполнения всех операций (
AllDone
),
а во-вторых, продолжительность тайм-аута. После ответа каждого сервера различные
потоки пула будут вызывать метод
ComputeResult
класса
MultiWebRequests
. Этот
метод обрабатывает байты, возвращенные сервером (или любые ошибки), и сохра-
няет результат в словаре. После сохранения каждого
результата вызывается метод
JustEnded
класса
AsyncCoordinator
, позволяющий объекту
AsyncCoordinator
узнать о завершении операции.
После завершения всех операций объект
AsyncCoordinator
вызывает метод
AllDone
для обработки результатов, полученных со всех веб-серверов. Этот метод
будет выполняться потоком пула, последним получившим ответ с сервера. В
случае
завершения времени ожидания или отмены операции метод
AllDone
будет вызван
либо потоком пула, уведомляющим объект
AsyncCoordinator
о том, что время
закончилось, либо потоком, вызвавшим метод
Cancel
. Существует также вероят-
ность,
что поток, выполняющий запрос к серверу, сам вызовет метод
AllDone
, если
последний запрос завершится до вызова метода
AllBegin
.
Имейте в виду, что в данном случае имеет место ситуация гонки,
так как воз-
можно одновременное завершение всех запросов к серверам, вызов метода
AllBegun
,
завершение времени ожидания и вызов метода
Cancel
. Если такое произойдет, объ-
ект
AsyncCoordinator
выберет победителя, гарантируя,
что метод
AllDone
будет
вызван не более одного раза. Победитель указывается передачей в метод
AllDone
аргумента состояния, роль которого может играть одно из символических имен,
определенных в типе
CoordinationStatus
:
internal enum CoordinationStatus { AllDone, Timeout, Cancel };
1
Код будет работать корректно, даже если вызвать метод m_ac.AboutToBeging(m_requests.
Length) всего один раз перед циклом вместо вызова метода AboutToBegin внутри цикла.