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百万的数组在看看结果:

很明显,并行反倒比串行慢!!!,这一点请大家一定要注意,不要想当然认为并行一定比串行快。
F# 天生就是就异步和并行的料的更多相关文章
- 【原】iOS多线程之异步任务+并行队列情况与异步任务+串行队列(主队列)情况
异步任务+并行队列 把异步任务放到并行队列进行执行,异步任务会在不同的线程中执行. /*异步执行+并行队列*/ - (IBAction)clickBasic1:(UIButton *)sender { ...
- iOS:转载:同步、异步、并行、串行的详解
理解 iOS 开发中 GCD 相关的同步(synchronization)\ 异步(asynchronization),串行(serial)\ 并行(concurrency)概念 2014年11月21 ...
- swoolefy PHP的异步、并行、高性能网络通信引擎内置了Http/WebSocket服务器端/客户端
近半年来努力付出,项目终于要正式结项了,团队4人经历了很多困难,加班加点,最终完成了!剩下的时间将总结一下在该项目中用到知识和遇到问题.今天就从swoole说起!项目中实现异步大文件传输的功能,在服务 ...
- C# 【一】进程 , 线程 , 微线程 , 同步 , 异步 , 并发 , 并行 , 阻塞 , 非阻塞
一 理解篇 前言 本文仅仅用作借鉴使用,作者刚入行不久,所以请不小心看到这篇文章的朋友,手下留情. 本文以小故事的形式进行叙述,逻辑不通之处.请理解. 如有错误 ,欢迎指出. 谢谢. ...
- iOS:对GCD中 同步、异步、并行、串行的见解
1.GCD-同步执行多线程时 GCD中不管向什么类型的队列加同步任务,实际上都会加到当前线程中(一般为主线程). 2.GCD-异步执行多线程时 GCD中不管向什么类 ...
- 异步与并行~List<T>是线程安全的吗?
返回目录 题目有点意思,大家都知道Dictionary<K,V>不是线程安全的类型,而List<T>是线程安全的吗?在今天之前大叔没有去测试过,而就在今天也是一个VIP问我,说 ...
- 异步与并行~ReaderWriterLockSlim实现的共享锁和互斥锁
返回目录 在System.Threading.Tasks命名空间下,使用ReaderWriterLockSlim对象来实现多线程并发时的锁管理,它比lock来说,性能更好,也并合理,我们都知道lock ...
- 进程、线程、GIL、同步、异步、并行、并发、互斥锁
- 异步与并行~CancellationTokenSource对线程的作用
返回目录 说起CancellationTokenSource我们应该不会陌生,对于Thread,Task来说,我们启动一个线程去做一些事,如果希望它在某个阶段去被动的停止,可以使用这个Cancella ...
随机推荐
- 武汉科技大学ACM :1003: 零起点学算法67——统计字母数字等个数
Problem Description 输入一串字符,统计这串字符里的字母个数,数字个数,空格字数以及其他字符(最多不超过100个字符) Input 多组测试数据,每行一组 Output 每组输出一行 ...
- 网络流——增广路算法(dinic)模板 [BeiJing2006]狼抓兔子
#include<iostream> #include<cstring> #include<algorithm> #include<cmath> #in ...
- Linux 常用命令使用方法大搜刮
Linux 常用命令使用方法大搜刮 1.# 表示权限用户(如:root),$ 表示普通用户 开机提示:Login:输入用户名 password:输入口令 用户是系统注册用户成功登陆后,可以进入 ...
- php 之 PDO数据访问抽象层(0513)
PDO(PHP Data Objects)是一种在PHP里连接数据库的使用接口. PDO与mysqli曾经被建议用来取代原本PHP在用的mysql相关函数, 基于数据库使用的安全性,因为后者欠缺对于S ...
- js动态给table添加行(tr)
html <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> < ...
- data语意学
引例: class X{}; class Y:public virtual X{}; class Z:public virtual X{}; class A:public Y,public Z{}; ...
- 通过select选项动态异步加载内容
通过监听select的change事件来异步加载数据. 1:效果图: 选择Good: 选择 Bad: 2:index.html <!DOCTYPE html> <html lang= ...
- 树上莫队 wowow
构建:像线性的莫队那样,依旧是按sqrt(n)为一块分块. int dfs(int x){ ; dfn[x]=++ind; ;i<=;i++) if (bin[i]<=deep[x]) f ...
- SQL基础理论题
sql理论题 1.触发器的作用? 答:触发器是一中特殊的存储过程,主要是通过事件来触发而被执行的.它可以强化约束,来维护数据的完整性和一致性,可以跟踪数据库内的操作从而不允许未经许可的更新和变化.可以 ...
- 【转】Ubuntu 10.04 LTS 的窗口控制按钮从左上角调整到右上角
原文网址:http://www.linuxidc.com/Linux/2010-05/26111.htm 升级到Ubuntu 10.04后最大的问题,是最小最大和关闭按钮,放到了左边.这叫Ubuntu ...