2012-03-28 207 views
1

我从Bloomberg API检索数据,并且对缓慢感到非常惊讶。 我的计算是由此限制的IO。将线程阻塞转换为f中的非线程阻塞#

因此,我决定使用一些异步monad生成器来取消它。 运行它后,结果并没有那么好,这是显而易见的,因为我调用了线程阻塞的函数NextEvent。

 let outerloop args dic = 
     ... 
     let rec innerloop continuetoloop = 
      let eventObj = session.NextEvent(); //This blocks 
      ... 

    let seqtable = reader.ReadFile(@"C:\homeware\sector.csv", ";".[0], true) 

    let dic = ConcurrentDictionary<_,_>() 
    let wf = seqtable |> Seq.mapi (fun i item -> async { outerloop item dic }) 
    wf |> Async.Parallel 
     |> Async.RunSynchronously 
     |> ignore 
    printfn "%A" ret 

是否有来包装到阻塞调用非阻塞通话的好办法? 此外,为什么异步框架没有创建尽可能多的线程,因为我有请求(如200)?当我检查我从中得到的值我看到的只有4-5所使用的线程..

UPDATE

我发现为什么它会永远不可能令人信服的理由。 异步操作使用异步指令后的内容并将其安排在线程池中的某处。只要异步函数的使用是正确的,也就是说,总是返回它所源自的线程池,我们可以认为我们是在一个线程上执行。

单线程意味着所有的调度将总是在稍后的某个地方执行,并且阻塞指令无法避免这样的事实:最终一旦它运行,它将不得不在未来某个时刻阻塞worflow。

+0

如何创建200个线程以任何方式帮助您?如果你有200个连接,你将有200个非常慢的连接,而不是几个快速连接。 (不提200 MB的开销。) – svick 2012-03-28 11:12:41

+0

另外,如果你的操作是IO阻塞,那么使用更多的CPU不会给你带来太多好处。速度很慢,因为网络速度很慢,并且您不会通过使用更多线程来提高网络速度。 – svick 2012-03-28 11:23:14

+0

@svick为什么连接IO计算速度慢的连接不会比5个慢速连接好40倍?我可以看到它现在正在处理40个5个操作,这可以通过200个操作中的1个操作更好地处理。或者我错过了什么? – nicolas 2012-03-28 12:18:20

回答

2

有没有一种很好的方法将该阻塞呼叫包裹到非阻塞呼叫?

不可以。您永远无法打包阻止的呼叫以使它们成为非阻塞。如果可以的话,异步只是一种设计模式,而不是一种基本的范式转变。

此外,为什么异步框架没有创建尽可能多的线程,因为我有请求(如200)?

异步建立在线程池上,线程池被设计为不积极创建线程,因为它们非常昂贵。 (真正的)异步的完整点在于,它不需要与连接一样多的线程。您可以使用约30个线程处理10,000个同时连接。

您似乎对异步是什么以及它是什么有一个完全的误解。我建议购买任何涵盖此主题并阅读它的F#书籍。特别是,您的解决方案不是异步的,因为您只需在异步工作流程内调用您的阻止StartGetFieldsValue成员,就会破坏异步的目的。您可能只需做Array.Parallel.map getFieldsValue

此外,您希望在并行执行某些操作时使用纯功能API,而不是在原地进行变异ConcurrentDictionary。因此,与

let! result = req.StartGetFieldsValue() 
... 
return result 

取代req.StartGetFieldsValue retdict取代ignore

+0

我并不希望为第一个pb使用异步解决方案。正如我读到的,asyncs只是CPS重写。 (对于字典而言,如果对这个特定的API来说效率不高,可能会在几个字段上对多个证券进行请求,并且信息会逐位进入。什么是最有意义的最小单位?可能是一个很好的方式来打包它,但我不知道它) – nicolas 2012-03-30 22:38:12

+0

说,我肯定会读一些材料,因为必须有一种方法来映射这个API很好.. – nicolas 2012-03-30 22:39:35

+0

你的评论让我想到了什么是真正的异步计算。虽然我们可以说它们只是CPS重写,但这只是形成代码的一部分。如果我对此没有错,真实的故事是异步计算是针对*线程池*什么同步计算针对*线程*。这就是为什么他们大多数时候感觉像是同步计算。正如你所指出的,线程池对于我们99%的时间所做的工作非常有用,异步结构反映了这种能力。 – nicolas 2012-03-31 13:21:58

0

这是我所做的似乎正在工作的解决方案。 当然,它不仅使用异步(减号),而且使用异步。

我定义具有一个事件,精加工,和一种方法,asyncstart简单类型,具有作为参数运行的方法。它启动方法,然后触发在适当的地方完成的情况下(在我的情况,我不得不捕捉同步上下文等)

然后在消费者方面,我用简单的

let! completion = Async.Waitfromevent wapper.finished |> Async.StartAsChild 
let! completed = completion 

虽然运行这个代码,在消费者方面,我只使用异步调用,使我的代码不被阻塞。当然,必须有一些线程被阻塞,但这种情况发生在我的主要服务环路之外,它仍然是被动和适应的。