Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/flash/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
F# 异步爬网#_F#_Web Crawler - Fatal编程技术网

F# 异步爬网#

F# 异步爬网#,f#,web-crawler,F#,Web Crawler,在网页上爬行时,我需要小心,不要对同一个域发出太多请求,例如,我希望在请求之间放置1s。据我所知,请求之间的时间是重要的。因此,为了加快速度,我想在F#中使用异步工作流,其思想是以1秒的间隔发出请求,但避免在等待请求响应时阻塞 let getHtmlPrimitiveAsyncTimer (uri : System.Uri) (timer:int) = async{ let req = (WebRequest.Create(uri)) :?> HttpW

在网页上爬行时,我需要小心,不要对同一个域发出太多请求,例如,我希望在请求之间放置1s。据我所知,请求之间的时间是重要的。因此,为了加快速度,我想在F#中使用异步工作流,其思想是以1秒的间隔发出请求,但避免在等待请求响应时阻塞

let getHtmlPrimitiveAsyncTimer (uri : System.Uri) (timer:int) =
    async{

            let req =  (WebRequest.Create(uri)) :?> HttpWebRequest
            req.UserAgent<-"Mozilla"
            try 

                Thread.Sleep(timer)
                let! resp =    (req.AsyncGetResponse())
                Console.WriteLine(uri.AbsoluteUri+" got response")
                use stream = resp.GetResponseStream()
                use reader = new StreamReader(stream)
                let html = reader.ReadToEnd()
                return html
            with 
            | _ as ex -> return "Bad Link"
                 }
这样行吗?我对两件事非常不确定: -Thread.Sleep事件是否能延迟请求? -使用StartTask是否存在问题

我是F#的初学者(正如您可能已经注意到的那样)(实际上是一般的编码),所有围绕线程的东西都让我害怕:)


谢谢

我想你想做的是 -创建10个编号为“n”的作业,每个作业从现在起开始“n”秒 -把它们并行运行

近似

let makeAsync uri n = async {
    // create the request
    do! Async.Sleep(n * 1000)
    // AsyncGetResponse etc
    }

let a = [| for i in 1..10 -> makeAsync uri i |]
let results = a |> Async.Parallel |> Async.RunSynchronously
请注意,当然它们现在不会完全启动,例如,如果您有一台4核机器,4将很快开始运行,但随后将快速执行到Async.Sleep,此时下一台4将运行到睡眠状态,依此类推。然后在一秒钟内第一个异步唤醒并发出请求,另一秒钟后第二个异步唤醒。。。所以这应该行得通。1只是一个近似值,因为它们启动计时器时,每个计时器彼此都有一点点的交错。。。如果您需要的截止时间正好是一秒钟,您可能需要对其进行一点缓冲,例如1100毫秒或其他什么(网络延迟等可能仍会使您的程序无法控制)

Thread.Sleep
是次优的,它可以处理少量的请求,但是您正在烧掉一个线程,而且线程非常昂贵,而且无法扩展到大量

您不需要
startask
,除非您希望与.NET任务互操作,或稍后通过
.result
与结果进行阻塞会合。如果您只想让它们全部运行,然后阻塞以在一个数组中收集所有结果,
Async.Parallel
将为您完成fork-join-parallelism。如果他们只是要打印结果,您可以通过
Async.Start
启动并忘记,这样会将结果放在地板上


(另一种策略是使用代理作为节流阀。将所有http请求发布到单个代理,该代理在逻辑上是单线程的,并处于循环中,执行
Async.Sleep
,持续1s,然后处理下一个请求。这是一种很好的方法,可以使通用节流阀…对我来说可能是值得写博客的,想想看)我想你想做的是 -创建10个编号为“n”的作业,每个作业从现在起开始“n”秒 -把它们并行运行

近似

let makeAsync uri n = async {
    // create the request
    do! Async.Sleep(n * 1000)
    // AsyncGetResponse etc
    }

let a = [| for i in 1..10 -> makeAsync uri i |]
let results = a |> Async.Parallel |> Async.RunSynchronously
请注意,当然它们现在不会完全启动,例如,如果您有一台4核机器,4将很快开始运行,但随后会快速执行到Async.Sleep,此时下一个4将运行到睡眠状态,依此类推。然后在一秒钟内第一个Async唤醒并发布请求,另一秒钟后第二个Async将作为ync唤醒,…所以这应该是可行的。1s只是近似值,因为它们启动计时器时彼此之间的间隔非常小……如果您需要的截止时间确实是一秒钟,您可能需要缓冲一下,例如1100毫秒或其他什么(网络延迟和诸如此类的事情仍然会让您的程序无法控制)

Thread.Sleep
是次优的,它可以处理少量的请求,但是您正在烧掉一个线程,而且线程非常昂贵,而且无法扩展到大量

你不需要
startask
,除非你想与.NET任务互操作,或者以后通过
.result
与结果进行阻塞会合。如果你只想让这些都运行,然后阻塞以收集数组中的所有结果,
Async.Parallel
将为你做一个fork-join并行e只要打印结果,您就可以通过
Async.Start
启动并忘记,这将把结果扔到地板上


(另一种策略是使用代理作为节流阀。将所有http请求发布到单个代理,该代理在逻辑上是单线程的,并处于循环中,执行
Async.Sleep
,持续1s,然后处理下一个请求。这是一种很好的方法,可以使通用节流阀…对我来说可能是值得写博客的,想想看)呵呵!非常非常好,谢谢。F#真是太棒了,我喜欢“Async.Parallel”能帮你做到这一点:),对于像我这样的初学者来说,它让你担心代码是否正确。谢谢!已经取得了进展:事实上,Brian,我不确定这个解决方案是否适用于大量uri,或者是真的吗?请看我在那里的回答;那里的问题与这里的问题不同,因为在这里,你预先知道所有uri,并立即启动所有操作,而您在程序运行期间发现了新的URI。是的,谢谢您看到了,正在使用:)。在这篇文章中,在一个非常大的异步元素序列上同步启动|>Asyn.Parallel |>Asyn.RunSynchronously是没有问题的?呵呵!非常好,谢谢。F#真的很神奇,我喜欢“Async.Parallel”可以为您做到这一点:),对于像我这样的初学者来说,它让你担心代码是否正确。非常感谢。已经取得了进展:实际上,Brian,我不确定这个解决方案是否适用于大量uri,或者它是否有效?请参见我的回答;这里的问题与这里的问题不同,因为在这里您预先知道所有URI并立即启动所有URI,而在那里您在程序运行期间发现了新的URI。是的,谢谢您看到了它,正在处理它:)。对于这篇文章,在一个非常大的异步元素序列上同步启动|>Asyn.Parallel |>Asyn.runsynchronous没有问题吗?