了解F#异步编程 [英] Understanding F# Asynchronous Programming

查看:119
本文介绍了了解F#异步编程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我种知道F#异步编程的语法。例如。

 让downloadUrl(网址:字符串)= {异步
  让REQ = HttpWebRequest.Create(URL)
  //运行异步操作
  让! RESP = req.AsyncGetResponse()
  让流= resp.GetResponseStream()
  //处置的StreamReader完成时
  使用读卡器=新的StreamReader(流)
  //异步运行,然后返回结果
  返回! reader.AsyncReadToEnd()}

在F#专家的书(和许多其他来源),他们说像


  

让! VAR = EXPR仅仅意味着执行异步操作
  EXPR并将结果结合到VAR在操作完成时。然后
  通过执行计算身体的其余部分继续


我也知道,在执行异步操作,当一个新线程被创建。我原来的理解是,有异步操作后,两个平行线程,一个做I / O和一个继续在同一时间执行异步身体。

但是,在这个例子中,我在

很困惑

 让! RESP = req.AsyncGetResponse()
  让流= resp.GetResponseStream()

会发生什么,如果 RESP 还未开始,并在体内异步线程想要 GetResponseStream ?这是一个可能的错误?

所以,也许我的最初理解是错误的。在F#专家书中提到的判决实际上意味着创造一个新的线程,挂起当前线程时,当新的线程结束,唤醒身体线并继续,但在这种情况下,我不认为我们可以节省任何时候。

在原来的理解,当有几个独立的IO操作在一个异步块,使他们能在同一时间进行,而不互相干预节省时间。但在这里,如果我没有得到回应,我不能创建流;只有我有流,我就可以开始读流。哪来的时间得到了什么?


解决方案

在这个例子中的异步是不是并发或节省时间,而它是关于提供了一个良好的编程模型,而不会阻塞(读:浪费)。线程

如果使用其他编程语言,通常有两种选择:

您可以阻止后,通常通过调用同步方法。缺点是该线程被消耗,做任何有用的工作,而它等待磁盘或网络I / O或你有什么。它的优点是它code简单(正常code)。

您可以使用回调以异步调用,当操作完成得到通知。它的优点是你不阻塞线程(这些线程可以例如被返回到线程池,当操作完成给您回电话一个新的线程池的线程将被使用)。缺点是code的简单块被划分成一堆回调方法或lambda表达式,并迅速变得非常复杂,维护国家/控制流/异常处理跨回调。

所以你是在岩石与险境间;你要么放弃简单的编程模型,或者你浪费线程。<​​/ P>

在F#模型给出了两全其美;你不阻止线程,但你保持简单的编程模型。构造,如让!使您能够在一个异步块的中间线程跳,所以在code像

  Blah1()
让! X = AsyncOp()
Blah2()

Blah1 可能运行,比如说,线程池线#13,但随后AsyncOp将释放该线程返回线程池。后来AsyncOp完成时,在code的其余部分将启动备份上的可用线程(也许,比如说,线程池线#20)结合 X 来的结果,然后运行 Blah2 。在平凡的客户端应用,那么此并不重要,(确保你不阻止UI线程时除外),但在服务器上的应用程序,I / O操作(如线程往往是precious资源 - 线程是昂贵的,你不能通过阻断浪费它们)非阻塞I / O通常是进行一个大规模应用的唯一途径。 F#使您能够编写非阻塞I / O,而无需程序降解成spaghetti- code回调的质量。

另请参见

<一个href=\"http://stackoverflow.com/questions/496468/f-best-practices-to-parallelize-using-async-workflow\">http://stackoverflow.com/questions/496468/f-best-practices-to-parallelize-using-async-workflow

<一个href=\"http://stackoverflow.com/questions/1468145/how-to-do-chained-callbacks-in-f\">http://stackoverflow.com/questions/1468145/how-to-do-chained-callbacks-in-f

<一个href=\"http://cs.hubfs.net/forums/thread/8262.aspx\">http://cs.hubfs.net/forums/thread/8262.aspx

I kind of know the syntax of asynchronous programming in F#. E.g.

let downloadUrl(url:string) = async { 
  let req = HttpWebRequest.Create(url)
  // Run operation asynchronously
  let! resp = req.AsyncGetResponse()
  let stream = resp.GetResponseStream()
  // Dispose 'StreamReader' when completed
  use reader = new StreamReader(stream)
  // Run asynchronously and then return the result
  return! reader.AsyncReadToEnd() }

In F# expert book (and many other sources), they say like

let! var = expr simply means "perform the asynchronous operation expr and bind the result to var when the operation completes. Then continue by executing the rest of the computation body"

I also know that a new thread is created when performing async operation. My original understanding was that there are two parallel threads after the async operation, one doing I/O and one continuing to execute the async body at the same time.

But in this example, I am confused at

  let! resp = req.AsyncGetResponse()
  let stream = resp.GetResponseStream()

What happens if resp has not started yet and the thread in the async body wants to GetResponseStream? Is this a possible error?

So maybe my original understanding was wrong. The quoted sentences in the F# expert book actually means that "creating a new thread, hang the current thread up, when the new thread finishes, wake up the body thread and continue", but in this case I don't see we could save any time.

In the original understanding, the time is saved when there are several independent IO operations in one async block so that they could be done at the same time without intervention with each other. But here, if I don't get the response, I cannot create the stream; only I have stream, I can start reading the stream. Where's the time gained?

解决方案

The "async" in this example is not about concurrency or saving time, rather it's about providing a good programming model without blocking (read: wasting) threads.

If using other programming languages, typically you have two choices:

You can block, typically by calling synchronous methods. The disadvantage is that the thread is consumed and doing no useful work while it waits for the disk or network I/O or what have you. The advantage is it the code simple (normal code).

You can use callbacks to call asynchronously and get notifications when operations complete. The advantage is you don't block threads (these threads can be returned e.g. to the ThreadPool and a new ThreadPool thread will be used when the operation completes to call you back). The disadvantage is that a simple block of code gets divided up into a bunch of callback methods or lambdas, and it quickly becomes very complicated to maintain state/control-flow/exception-handling across the callbacks.

So you're between a rock and a hard place; you either give up the simple programming model or you waste threads.

The F# model gives the best of both worlds; you don't block threads, but you keep the straightforward programming model. Constructs like let! enable you to 'thread-hop' in the middle of an async block, so in code like

Blah1()
let! x = AsyncOp()
Blah2()

Blah1 may run on, say, ThreadPool thread #13, but then AsyncOp will release that thread back to the ThreadPool. Later when the AsyncOp completes, the rest of the code will start back up on an available thread (maybe, say, ThreadPool thread #20) which binds x to the result and then runs Blah2. In trivial client apps this rarely matters (except when ensuring you don't block the UI thread), but in server apps that do I/O (where threads are often a precious resource - threads are expensive and you can't waste them by blocking) non-blocking I/O is often the only way to make an application scale. F# enables you to write non-blocking I/O without having the program degrade into a mass of spaghetti-code callbacks.

See also

http://stackoverflow.com/questions/496468/f-best-practices-to-parallelize-using-async-workflow

http://stackoverflow.com/questions/1468145/how-to-do-chained-callbacks-in-f

http://cs.hubfs.net/forums/thread/8262.aspx

这篇关于了解F#异步编程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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