我正在尝试实现我从Don Syme的博客中读到的模式
这表明利用异步I/O可以大幅提升性能.我目前正在尝试使用Array.Parallel.Map以一种方式"工作"一段代码,看看我是否可以使用Async.Parallel以某种方式实现相同的结果,但我真的不明白Async.Parallel,并且无法获得任何工作.
我有一段代码(下面简化说明这一点)成功检索一个cusip的数据数组.(例如价格系列)
let getStockData cusip =
let D = DataProvider()
let arr = D.GetPriceSeries(cusip)
return arr
let data = Array.Parallel.map (fun x -> getStockData x) stockCusips
Run Code Online (Sandbox Code Playgroud)
因此,这种方法构建了一个数组阵列,通过互联网连接到我的数据供应商为每个股票(可能多达3000个)并返回一个数组(每个股票1个,每个股票的价格序列)一).我当然不明白Array.Parallel.map下面发生了什么,但是我想知道这是否是浪费资源的情况,并且它实际上可以更快地使用异步I/O?所以为了测试它,我试图使用asyncs来创建这个函数,我认为下面的函数遵循Don Syme使用URL的文章中的模式,但它不会使用"let!"进行编译.
let getStockDataAsync cusip =
async { let D = DataProvider()
let! arr = D.GetData(cusip)
return arr
}
Run Code Online (Sandbox Code Playgroud)
我得到的错误是:此表达式应该具有类型Async <'a>但这里有类型obj
它用"let"而不是"let!"来编译很好,但我认为整个问题是你需要感叹号才能使命令在不阻塞线程的情况下运行.
所以第一个问题确实是,上面我的语法有什么问题,在getStockDataAsync中,然后在更高的层次上,任何人都可以提供一些关于异步I/O的额外见解,以及我提出的场景是否会从中受益,使其潜在比Array.Parallel.map更快,更快?非常感谢.
Tom*_*cek 21
F#异步工作流允许您实现异步计算,但是,F#区分了常规计算和异步计算.这种差异由类型系统跟踪.例如,下载网页并且是同步的方法具有类型string -> string(获取URL并返回HTML),但是异步执行相同操作的方法具有类型string -> Async<string>.在async块中,您可以使用let!调用异步操作,但必须使用所有其他(标准同步)方法let.现在,您的示例的问题是该GetData操作是普通的同步方法,因此您无法使用它来调用它let!.
在典型的F#场景中,如果要使GetData成员异步,则需要使用异步工作流实现它,因此您还需要将其包装在async块中.在某些时候,您将到达一个您真正需要异步运行某些原始操作的位置(例如,从网站下载数据).F#提供了几个原始异步操作,您可以async使用let!诸如AsyncGetResponse(这是GetResponse方法的异步版本)从块调用.所以,在你的GetData方法中,你将例如写下这样的东西:
let GetData (url:string) = async {
let req = WebRequest.Create(url)
let! rsp = req.AsyncGetResponse()
use stream = rsp.GetResponseStream()
use reader = new System.IO.StreamReader(stream)
let html = reader.AsyncReadToEnd()
return CalculateResult(html) }
Run Code Online (Sandbox Code Playgroud)
总结是您需要识别一些原始异步操作(例如等待Web服务器或文件系统),在该点使用原始异步操作并将所有使用这些操作的代码包装在async块中.如果没有可以异步运行的基本操作,那么您的代码是CPU限制的,您可以使用Parallel.map.
我希望这有助于您了解F#异步工作流程的工作原理.有关更多信息,您可以查看Don Syme的博客文章,关于Robert Pickering的异步编程系列,或者我的F#网络广播.
@Tomas已经有了很好的答案.我还要说几句话.
F#asyncs的习惯用法是用"异步"前缀命名方法(AsyncFoo不是FooAsync;后者是另一种.NET技术已经使用过的习惯用法).所以你的功能应该getStockData和asyncGetStockData.
在异步工作流程中,无论何时使用let!而不是let或do!代替do,右边的东西应该有类型Async<T>而不是T.基本上,您需要一个现有的异步计算,以便在工作流程中的此时"异步".每个都Async<T>将是其他async{...}工作流程,或者是异步"原始".的原语的F#库中定义,或通过在用户代码中创建Async.FromBeginEnd或Async.FromContinuations其能够限定在开始计算,注册一个I/O回调,释放线程,然后重新启动计算时获取调用背面的低级别的细节.因此,为了获得异步I/O的全部好处,您必须将"异步"同步到一些真正的异步I/O原语.
| 归档时间: |
|
| 查看次数: |
3349 次 |
| 最近记录: |