我正在从网站域名列表的前端抓取一些数据。他们中的一些人没有回答,或者说很慢,导致刮刀停止。
我想通过使用超时来解决这个问题。可用的各种HTTP库似乎不支持,但System.Timeout.timeout似乎做了我需要的。
实际上,当我测试抓取功能时似乎工作正常,但是当我运行封闭功能时它会崩溃:(对不起/丑陋的代码抱歉。我正在学习。)
fetchPage domain =
-- Try to read the file from disk.
catch
(System.IO.Strict.readFile $ "page cache/" ++ domain)
(\e -> downloadAndCachePage domain)
downloadAndCachePage domain =
catch
(do
-- Failed, so try to download it.
-- This craches when called by fetchPage, but works fine when called from directly.
maybePage <- timeout 5000000 (simpleHTTP (getRequest ("http://www." ++ domain)) >>= getResponseBody)
let page = fromMaybe "" maybePage
-- This mostly works, but wont timeout if the domain is slow. (lswb.com.cn)
-- page <- (simpleHTTP (getRequest ("http://www." ++ domain)) >>= getResponseBody)
-- Cache it.
writeFile ("page cache/" ++ domain) page
return page)
(\e -> catch
(do
-- Failed, so just fuggeddaboudit.
writeFile ("page cache/" ++ domain) ""
return "")
(\e -> return "")) -- Failed BIG, so just don't give a crap.
当从repl调用时,downloadAndCachePage可以正常使用超时,但是fetchPage崩溃了。如果我从downloadAndCachePage中删除超时,fetchPage将起作用。
任何能够解释这一点或知道替代解决方案的人?
答案 0 :(得分:1)
你在fetchPage中的catch处理程序看起来是错误的 - 看起来你正在尝试读取一个文件,而在文件中找不到异常会直接从异常处理程序调用你的http函数。不要这样做。由于复杂的原因,我记得,异常处理程序中的代码并不总是像普通代码一样 - 特别是当它试图自己处理异常时。实际上,在底层,超时使用异步异常来杀死线程。
通常,您应该在异常处理程序中放置尽可能少的代码,尤其不要放置尝试处理进一步异常的代码(尽管将处理的异常重新加载到“传递它”通常很好[与{一样] {1}}])。
也就是说,即使你没有做正确的事情,崩溃(如果它是一个段错误类型崩溃而不是bracket
类型崩溃),即使是奇怪的代码,也几乎总是错误的行为来自GHC,如果您使用GHC 7,那么您应该考虑报告此事。