Async.Parallel还是Array.Parallel.Map? [英] Async.Parallel or Array.Parallel.Map?

查看:97
本文介绍了Async.Parallel还是Array.Parallel.Map?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试实现从Don Syme的博客中读取的模式

I'm trying to implement a pattern I read from Don Syme's blog

( https://blogs.msdn.microsoft.com/dsyme/2010/01/09/async-and-parallel-design-patterns-in-f-parallelizing-cpu-and -io-computations/)

这表明利用异步I/O可以带来大量性能改进的机会.我目前正在尝试使用Array.Parallel.Map来采用一种工作"方式的代码,并查看是否可以通过Async.Parallel以某种方式实现相同的结果,但是我真的不理解Async.Parallel,并且什么也无法工作.

which suggests that there are opportunities for massive performance improvements from leveraging asynchronous I/O. I am currently trying to take a piece of code that "works" one way, using Array.Parallel.Map, and see if I can somehow achieve the same result using Async.Parallel, but I really don't understand Async.Parallel, and cannot get anything to work.

我有一段代码(下面简化以说明要点),可以成功地为一个cusip检索数据数组. (例如,一个价格序列)

I have a piece of code (simplified below to illustrate the point) that successfully retrieves an array of data for one cusip. (A price series, for example)

let getStockData cusip = 
    let D = DataProvider()
    let arr = D.GetPriceSeries(cusip)
    return arr

let data = Array.Parallel.map (fun x -> getStockData x) stockCusips

因此,这种方法通过在互联网上为每只股票(可能多达3000个)与我的数据供应商建立连接来构造一个数组阵列,并向我返回一个数组阵列(每只股票1个,价格为系列的每个).我承认我不理解Array.Parallel.map下发生了什么,但是我想知道这是否是一种浪费资源的方案,而使用异步I/O可能会更快?因此,为了测试这一点,我尝试使用异步来实现此功能,并且我认为下面的功能遵循Don Syme文章中使用URL的模式,但不会使用"let!"进行编译.

So this approach contructs an array of arrays, by making a connection over the internet to my data vendor for each stock (which could be as many as 3000) and returns me an array of arrays (1 per stock, with a price series for each one). I admittedly don't understand what goes on underneath Array.Parallel.map, but am wondering if this is a scenario where there are resources wasted under the hood, and it actually could be faster using asynchronous I/O? So to test this out, I have attempted to make this function using asyncs, and I think that the function below follows the pattern in Don Syme's article using the URLs, but it won't compile with "let!".

let getStockDataAsync cusip = 
    async {  let D = DataProvider()
             let! arr = D.GetData(cusip)
             return arr
          } 

我得到的错误是: 预期该表达式的类型为Async<'a>,但此处的类型为obj

The error I get is: This expression was expected to have type Async<'a> but here has type obj

使用"let"而不是"let!"可以正常编译,但是我认为整个要点是,您需要使用感叹号才能使命令在不阻塞线程的情况下运行.

It compiles fine with "let" instead of "let!", but I had thought the whole point was that you need the exclamation point in order for the command to run without blocking a thread.

所以第一个问题确实是,在getStockDataAsync中,我上面的语法有什么问题,然后在更高的层次上,谁能提供有关异步I/O的更多见解,以及我提出的方案是否将从中受益,是否可能比Array.Parallel.map快得多?非常感谢.

So the first question really is, what's wrong with my syntax above, in getStockDataAsync, and then at a higher level, can anyone offer some additional insight about asychronous I/O and whether the scenario I have presented would benefit from it, making it potentially much, much faster than Array.Parallel.map? Thanks so much.

推荐答案

F#异步工作流允许您实现异步计算,但是F#区分了常规计算和异步计算.这种差异由类型系统跟踪.例如,下载网页并同步的方法的类型为string -> string(采用URL并返回HTML),但是异步执行相同操作的方法的类型为string -> Async<string>.在async块中,可以使用let!调用异步操作,但是必须使用let调用所有其他(标准同步)方法.现在,您的示例的问题是GetData操作是普通的同步方法,因此您无法使用let!调用它.

F# asynchronous workflows allow you to implement asynchronous computations, however, F# makes a distinction between usual computation and asynchronous computations. This difference is tracked by the type-system. For example a method that downloads web page and is synchronous has a type string -> string (taking URL and returning HTML), but a method that does the same thing asynchronously has a type string -> Async<string>. In the async block, you can use let! to call asynchronous operations, but all other (standard synchronous) methods have to be called using let. Now, the problem with your example is that the GetData operation is ordinary synchronous method, so you cannot invoke it with let!.

在典型的F#场景中,如果要使GetData成员异步,则需要使用异步工作流来实现它,因此还需要将其包装在async块中.在某个时候,您将到达真正需要异步运行某些基本操作的位置(例如,从网站下载数据). F#提供了几种原始异步操作,您可以使用let!async块中调用这些操作,例如AsyncGetResponse(这是GetResponse方法的异步版本).因此,在您的GetData方法中,例如,您将编写如下内容:

In the typical F# scenario, if you want to make the GetData member asynchronous, you'll need to implement it using an asynchronous workflow, so you'll also need to wrap it in the async block. At some point, you will reach a location where you really need to run some primitive operation asynchronously (for example, downloading data from a web site). F# provides several primitive asynchronous operations that you can call from async block using let! such as AsyncGetResponse (which is an asynchronous version of GetResponse method). So, in your GetData method, you'll for example write something like this:

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) }

摘要是,您需要标识一些原始异步操作(例如,等待Web服务器或文件系统),在那一点上使用原始异步操作,并将使用这些操作的所有代码包装在async中块.如果没有可以异步运行的原始操作,则您的代码受CPU限制,您可以只使用Parallel.map.

The summary is that you need to identify some primitive asynchronous operations (such as waiting for the web server or for the file system), use primitive asynchronous operations at that point and wrap all the code that uses these operations in async blocks. If there are no primitive operations that could be run asynchronously, then your code is CPU-bound and you can just use Parallel.map.

我希望这可以帮助您了解F#异步工作流的工作方式.有关更多信息,您可以例如查看异步的系列Robert Pickering 或我的 F#网络广播进行编程.

I hope this helps you understand how F# asynchronous workflows work. For more information, you can for example take a look at Don Syme's blog post, series about asynchronous programming by Robert Pickering, or my F# web cast.

这篇关于Async.Parallel还是Array.Parallel.Map?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆