Для более широкого контекста, здесь мой код , который загружает список URL.
Мне кажется, что при использовании выборки URL в стиле use! response = request.AsyncGetResponse()
нет хорошего способа обработки таймаутов в F #. У меня почти все работает, как хотелось бы (обработка ошибок и асинхронная загрузка запросов и ответов), за исключением проблемы, которая возникает, когда веб-сайту требуется много времени для ответа. Мой текущий код просто висит бесконечно. Я пробовал это на написанном мной PHP-скрипте, который ждет 300 секунд. Ждал все время.
Я нашел «решения» двух видов, оба из которых нежелательны.
AwaitIAsyncResult
+ BeginGetResponse
Как и ответ ildjarn на этот другой вопрос переполнения стека . Проблема в том, что если вы поставили в очередь много асинхронных запросов, некоторые из них искусственно блокируются на AwaitIAsyncResult
. Другими словами, сделан запрос на выполнение запроса, но что-то закулисное блокирует вызов. Это приводит к преждевременному срабатыванию тайм-аута AwaitIAsyncResult
при выполнении множества одновременных запросов. Я предполагаю, что это ограничение на количество запросов к одному домену или просто ограничение на общее количество запросов.
Чтобы поддержать мои подозрения, я написал небольшое приложение WPF, чтобы нарисовать временную шкалу, когда запросы, кажется, начинаются и заканчиваются. В моем коде, указанном выше, обратите внимание на запуск и останов таймера в строках 49 и 54 (вызывающая строка 10). Вот результирующее изображение временной шкалы .
Когда я перемещаю начало таймера после первоначального ответа (поэтому я только рассчитываю время загрузки содержимого), временная шкала выглядит намного более реалистичной . Обратите внимание, что это два отдельных запуска, но без изменения кода, кроме места запуска таймера. Вместо того, чтобы измерять startTime
непосредственно перед use! response = request.AsyncGetResponse()
, я получаю его непосредственно после.
Для дальнейшей поддержки моего заявления я сделал график с Fiddler2 . Вот результирующий график времени . Очевидно, что запросы не начинаются точно, когда я им говорю.
GetResponseStream
в новой теме
Другими словами, синхронные запросы и вызовы загрузки выполняются во вторичном потоке. Это работает , так как GetResponseStream
учитывает свойство Timeout
объекта WebRequest
. Но в процессе мы теряем все время ожидания, так как запрос находится на связи, и ответ еще не вернулся. Мы могли бы также написать это на C # ...;)
Вопросы
- Это известная проблема?
- Есть ли какое-нибудь хорошее решение, которое использует асинхронные рабочие процессы F # и все еще допускает тайм-ауты и обработки ошибок?
- Если проблема действительно в том, что я делаю слишком много запросов одновременно, то будет ли лучшим способом ограничить количество запросов использование
Semaphore(5, 5)
или что-то подобное?
- Дополнительный вопрос: если вы посмотрели мой код, можете ли вы увидеть какие-то глупости, которые я сделал и мог исправить?
Если вас что-то смущает, пожалуйста, дайте мне знать.