F# 天生就是就异步和并行的料

做模型开发免不了要使用异步和并行计算,尤其在多核CPU的今天,更是如此,F#恰逢其时,天生就具备这种能力,先看一个例子。

open System

open System.Drawing

open System.Windows.Forms

open System.Threading

let r = Random()

let drawCurves (frm : Form) =

let x, y = frm.ClientSize.Width, frm.ClientSize.Height

let g = frm.CreateGraphics()

for i in 1..10 do

Thread.Sleep(300)

g.DrawCurve(Pens.Black, [|  for i in 1..5 -> Point(r.Next(x), r.Next(y)) |])

g.Dispose()

let drawRecs (frm : Form) =

let x, y = frm.ClientSize.Width, frm.ClientSize.Height

let g = frm.CreateGraphics()

for i in 1..10 do

Thread.Sleep(150)

g.DrawRectangle(Pens.Blue, r.Next(x), r.Next(y), r.Next(x/2), r.Next(y/2))

g.Dispose()

let drawElls (frm : Form) =

let x, y = frm.ClientSize.Width, frm.ClientSize.Height

let g = frm.CreateGraphics()

for i in 1..10 do

Thread.Sleep(150)

g.DrawEllipse(Pens.OrangeRed, r.Next(x), r.Next(y), r.Next(x/2), r.Next(y/2))

g.Dispose()

let frm1 = new Form(Text="随机图形", BackColor=Color.White)

frm1.DoubleClick.Add(fun e -> Async.RunSynchronously

(Async.Parallel ([ async { drawCurves frm1 };

async { drawRecs frm1 };

async { drawElls frm1 }

]))    |> ignore

)

Application.Run(frm1)

这是用F#编写的WinForm程序,是在Form上随机画矩形和椭圆和曲线,所不同是使用异步和并行方法实现的。

异步工作流

当使用.NET BCL的所有I/O操作的时候,有两个模型可用,同步模型和异步模型。异步模型是通过一个通用的编程模式来支持的,即成对出现的BeginXXX和 EndXXX方法。程序员通过调用BeginXXX来开始异步操作,这个方法开始执行后,就马上返回。而,程序员在得到异步操作已经结束的提醒后,必须调用EndXXX方法完成整个过程。这就是所谓的分两步实现异步操作。

而F#通过异步工作流来实现异步的,并不需要两步,只需要一步就行,这大大简化异步操作。

关键的 let! 异步绑定

在异步工作流中,一些表达式和操作是同步的,而另一些则是旨在以异步方式返回结果的较长时间的计算。 以异步方式调用一个方法时,使用let!,而不是普通的 let 绑定。 let! 的作用是允许在执行计算的同时,继续执行其他计算或线程。 在 let! 绑定的右侧返回后,异步工作流的剩余部分将继续执行。

在下面的代码示例中,函数 fetchAsync 将获取从 Web 请求返回的 HTML 文本。 fetchAsync 函数包含异步代码块。 在对异步基元的结果(此示例中为 AsyncDownloadString)执行绑定时,将使用 let!,而不是使用 let。

open System.Net

open Microsoft.FSharp.Control.WebExtensions

let urlList = [ "Microsoft.com", "http://www.microsoft.com/"

"MSDN", "http://msdn.microsoft.com/"

"Bing", "http://www.bing.com"

]

let fetchAsync(name, url:string) =

async {

try

let uri = new System.Uri(url)

let webClient = new WebClient()

let! html = webClient.AsyncDownloadString(uri)

printfn "Read %d characters for %s" html.Length name

with

| ex -> printfn "%s" (ex.Message);

}

let runAll() =

urlList

|> Seq.map fetchAsync

|> Async.Parallel

|> Async.RunSynchronously

|> ignore

runAll()

从这个例子可以看出,编写异步程序,跟编写同步程序差别不大,只是多了个let!和async块而已,多简单呢!

下面我们看看并行

F#使用Async.Parallel 方法构建一个工作流,将并行执行列表中的所有工作流。在执行时,由Async.Parallel组合而成的异步操作会通过一个等待计算的队列来逐步发起。Async.Parallel只能处理固定数量的任务,对于一边处理一边生成任务的情况不能胜任。换个方式来看,即Async.Parallel无法处理即时获得的消息──例如,除了取消任务之外,一个代理对象的工作进度是可以得到控制的。另外,F#还可以利用.NET的并行计算机制实现并行。

下面的例子是在一个随机3千万数组中求最大值代码,我们看看并行与串行比较结果。

open System

open System.Linq

open System.Diagnostics

let rand = System.Random()

let arr1 = [| for i in 0..1000000 -> float(rand.Next(1000000)) * rand.NextDouble() |]

let watch1 = Stopwatch()

watch1.Start()

let x = Seq.max arr1

watch1.Stop()

printfn "数组长度=%i, x=%.4f,  串行计算用时%i毫秒" arr1.Length x watch1.ElapsedMilliseconds

let watch2 = Stopwatch()

watch2.Restart()

let pArr1 = ParallelEnumerable.AsParallel arr1;

let x‘ = ParallelEnumerable.Max pArr1

watch2.Stop()

printfn "数组长度=%i, x=%.4f,  串行计算用时%i毫秒" arr1.Length x watch2.ElapsedMilliseconds

Console.ReadKey() |> ignore

在一台i3-2120CPU 3.3G惠普机器上运行的结果:

并行有性能明显优势。

那么是不是并行就一定比串行快呢?,我们把3千万的数组改为1百万的数组在看看结果:

很明显,并行反倒比串行慢!!!,这一点请大家一定要注意,不要想当然认为并行一定比串行快。

时间: 2024-08-25 23:37:01

F# 天生就是就异步和并行的料的相关文章

大话异步与并行(二)

接着上期的文章继续说异步与并行 并行来自于线程的方法实现,异步不一定.这句话,晕倒一大片程序员. 首先,多线程序是实现异步一种方法,两者的共同目的:使主线程保持对用户操作的实时响应,如点击.拖拽.输入字符等.使主程序看起来实时都保持着等待用户响应的状态,而后台却有若干件事情在自己干.按消耗资源所在地可分为两类:硬件异步类和CPU异步类. 硬件异步的特点:将需要在后台执行的操作甩给底层硬件去执行,不占用线程和CPU资源.所以说,并不是所有的异步都占有线程的. 硬件异步类大概有以下这几类. 应用程序

异步任务+并行队列情况与异步任务+串行队列(主队列)情况

异步任务+并行队列 把异步任务放到并行队列进行执行,异步任务会在不同的线程中执行. /*异步执行+并行队列*/ - (IBAction)clickBasic1:(UIButton *)sender { //全局并行队列 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //异步执行 dispatch_async(queue, ^{ for (int i = 0; i<2;

iOS:转载:同步、异步、并行、串行的详解

理解 iOS 开发中 GCD 相关的同步(synchronization)\ 异步(asynchronization),串行(serial)\ 并行(concurrency)概念 2014年11月21日iOSasynchronization.concurrency.GCD.iOS.serial.synchronization.串行.同步.并发.异步 iOS 开发过程中,常常需要用到多线程技术,GCD 是常用的实现多线程的技术,其因简洁底层而备受欢迎. GCD 技术中,同步(synchroniza

swoolefy PHP的异步、并行、高性能网络通信引擎内置了Http/WebSocket服务器端/客户端

近半年来努力付出,项目终于要正式结项了,团队4人经历了很多困难,加班加点,最终完成了!剩下的时间将总结一下在该项目中用到知识和遇到问题.今天就从swoole说起!项目中实现异步大文件传输的功能,在服务端使用了swoole,可以高效方便的实现,很多的项目其实也在用到swoole,突然间觉得swoole已经非常强大,对于phper来说,这是非常好的,可能大家都觉高大上了. 接下来将会以swoole为系列,总结一些swoole的知识,当然,官网文档有的这里就不会再多说,将会从应用场景,应用的技巧,和如

C# 【一】进程 , 线程 , 微线程 , 同步 , 异步 , 并发 , 并行 , 阻塞 , 非阻塞

一 理解篇 前言 本文仅仅用作借鉴使用,作者刚入行不久,所以请不小心看到这篇文章的朋友,手下留情. 本文以小故事的形式进行叙述,逻辑不通之处.请理解. 如有错误 ,欢迎指出. 谢谢.                                                           最后修改时间:2019-01-25 1.0.0 进程 老刘是一个软件公司的老板,公司下有两个部门,产品设计部门(产品进程)和研发部门(研发进程),产品设计部门在一楼,研发部门在二楼(独立地址空间).

异步与并行~List&lt;T&gt;是线程安全的吗?

返回目录 题目有点意思,大家都知道Dictionary<K,V>不是线程安全的类型,而List<T>是线程安全的吗?在今天之前大叔没有去测试过,而就在今天也是一个VIP问我,说在我的代码中使用了并行,然后为一个List赋值,说的直接一点就是:List元素是全局的,在各个线程里分别去操作它,测试数据是1万条,而在测试结果之后,我发展List元素最终的数组是9000多条,也就是说被并发了几千条数据,呵呵,下面咱们看一下源代码吧! 测试代码: [TestMethod] public vo

异步与并行~CancellationTokenSource对线程的作用

返回目录 说起CancellationTokenSource我们应该不会陌生,对于Thread,Task来说,我们启动一个线程去做一些事,如果希望它在某个阶段去被动的停止,可以使用这个CancellationTokenSource对象,把它注入到Task里,使用当外界触发Cancel()方法时,你的这个线程就会被取消了,挺好用,感觉应该是在Task内部封装的一种方法回周机制,在外部控制Task的状态! 看大叔的测试代码 CancellationTokenSource cancelTokenSou

[spring 并行4]异步

异步篇 1 介绍 2 除了线性.并行执行模式外,还有异步模式,它与事件编程一样,十分重要 在并发的异步模式中,不同的任务在时间线上是相互交错的,而且一切都是在单一控制流(单线程)下进行的 1.asyncio (过时) 基本使用 1.1 使用asyncio实现事件循环管理 什么是事件循环? 在计算系统中,能够产生事件的实体被称为事件源(event source),而负责协商管理事件的实体被称为事件处理器(event handler) 它实现了管理计算代码中所有事件的功能:在程序执行期间事件循环不断

并发 并行 同步 异步 多线程的区别

1. 并发:在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行.其中两种并发关系分别是同步和互斥2. 互斥:进程间相互排斥的使用临界资源的现象,就叫互斥.3. 同步:进程之间的关系不是相互排斥临界资源的关系,而是相互依赖的关系.进一步的说明:就是前一个进程的输出作为后一个进程的输入,当第一个进程没有输出时第二个进程必须等待.具有同步关系的一组并发进程相互发送的信息称为消息或事件.其中并发又有伪并发和真并发,伪并发是指单核处理器的并发,真并