ASP.NET教程之超出F#基本――异步事情流仓酷云
觉得J2EE好像有很多工具,比如servlet,jboss,tomcat,ejb什么的,可是微软的.NET怎么什么也没有啊?系列文章索引:《超出F#基本》我之前为InfoQ撰写的文章,《超出F#基本——事情流》,先容了事情流这类新言语特征。这篇文章将切磋一下称之为异步事情流的事情流特征的风趣用法,它的目标就是要简化.NET的异步编程模子。
甚么是F#?
F#是一个针对.NET框架的静态范例化函数式编程言语。它具有OCaml罕见的中心言语功效,和其他盛行的函数式编程言语的一些特征,并从良多其他编程言语猎取了一些头脑,包含Haskell、Erlang和C#。简而言之,这意味着F#是一个具有文雅语法的编程言语,当我们能交互式地实行代码的时分感到有点像剧本编程,可是它都是范例平安且有着优秀功能的编译言语。这篇文章不是F#的先容文章,不外收集上有良多资本可让我们简单地进修F#。能够参阅在我之前文章中的侧边栏所附加的一个“F#资本”列表。异步编程模子
当利用.NETBCL的一切I/O操纵的时分,有两个模子可用,同步模子和异步模子。异步模子是经由过程一个通用的编程形式来撑持的,即成对呈现的BeginXXX和EndXXX办法。程序员经由过程挪用BeginXXX来入手下手异步操纵,这个办法入手下手实行后,就即刻前往。而,程序员在失掉异步操纵已停止的提示后,必需挪用EndXXX办法完成全部历程。
以我的履历来看,年夜部分程序员都喜好用同步模子,这是因为它对照复杂,和在BCL中的良多类只撑持同步模子;不外在良多情形下,异步编程模子能发生呼应更敏捷更具伸缩性的使用程序。为了论述一下异步模子的坚苦的地方,让我们来看一个复杂的例子:翻开一个文件,从文件中读取字节,上面是一些完成同步处置的代码:
#lightopenSystem.IOletopenFile()=usefs=newFileStream(@"C:ProgramFilesInternetExploreriexplore.exe",FileMode.Open,FileAccess.Read,FileShare.Read)letdata=Array.create(intfs.Length)0uyletbytesRead=fs.Read(data,0,data.Length)printfn"ReadBytes:%i,Firstbyteswere:%i%i%i..."bytesReaddata.(1)data.(2)data.(3)openFile()BCL供应了一个更复杂的办法来完成下面的事变,便是“File.ReadAllBytes”,可是这个最复杂的体例却具有一个等效的异步利用体例。从文件中读取内容的操纵长短常刀切斧砍的:我们翻开一个文件流对象,创立一个数组来安排数据,最初把一切数据都读到这个数组中。注重,在创立文件流对象的时分我们是怎样利用“use”赋值语法的,这类用法大抵上和C#的using语句相称,即意味着文件流对象将在分开感化域的时分被烧毁失落。
如今,让我们来看一下利用异步编程模子的等效代码:
#lightopenSystem.IOletopenFile()=letfs=newFileStream(@"C:ProgramFilesInternetExploreriexplore.exe",FileMode.Open,FileAccess.Read,FileShare.Read)letdata=Array.create(intfs.Length)0uyletcallbackar=letbytesRead=fs.EndRead(ar)fs.Dispose()printfn"ReadBytes:%i,Firstbyteswere:%i%i%i..."bytesReaddata.(1)data.(2)data.(3)fs.BeginRead(data,0,data.Length,(funar->callbackar),null)|>ignoreopenFile()这个复杂的例子中,翻开文件的代码仍是简单了解的,不外接上去事变就很分明地变得越来越庞大了。一切步骤的第一步和之前的长短常的相似:翻开文件流对象,创立一个用于安排数据的数组。不外,从这里入手下手事变就变得有得糟了,我们必要界说一个回调来处置“EndRead”办法的挪用,这个回调必要陪伴着一个形态对象(在这里,因为我们不必要形态对象,以是传送的是空)传送到“BeginRead”办法中。也要重点注重的一个中央就是,我们不克不及再利用“use”语法了,这是由于文件流对象在挪用“BeginRead”办法的时分已分开了感化域了,如许就意味着假如利用“use”赋值语法,那末它不久便可能被烧毁失落,则当“EndRead”办法被挪用的时分它大概已不成用了。这也意味着,我们必要增加对“Dispose”办法的挪用,如许,我们会就损失在最初代码块(FinallyBlock)中挪用“Dispose”办法的平安措施。固然关于一个翻开文件的复杂例子来讲,这些分外的庞大操纵仿佛仍是对照公道,但当你增加更多功效和更进一步的异步读取才能到使用程序中的时分,你不久就会贫苦不休了。
异步事情流
异步事情流就是为了对付这个特别的成绩而引进的。那末,如今让我们来看看异步事情流的版本:
#lightopenSystem.IOopenMicrosoft.FSharp.Control.CommonExtensionsletopenFile=async{usefs=newFileStream(@"C:ProgramFilesInternetExploreriexplore.exe",FileMode.Open,FileAccess.Read,FileShare.Read)letdata=Array.create(intfs.Length)0uylet!bytesRead=fs.ReadAsync(data,0,data.Length)doprintfn"ReadBytes:%i,Firstbyteswere:%i%i%i..."bytesReaddata.(1)data.(2)data.(3)}Async.RunopenFile关于事情流版本要注重最主要的事变就是,它和同步版本的独一区分只是一小点字符。在“async{...}”事情流声明语句的到场后,更主要的是,我们要改动从文件读取内容的代码为:
let!bytesRead=fs.ReadAsync(data,0,data.Length)我们增加一个叹息号(!)到let关头字中,如今我们就能够挪用“ReadAsync”而非“Read”了。在异步事情流中,“let!”告知我们,接上去的赋值历程将利用异步的体例,而ReadAsync函数为BeginRead和EndRead办法怎样被挪用供应了标准。注重,假如我们不利用异步函数,那末我们就会失掉一个编译范例毛病。那末,“ReadAsync”来自那里?它不是一个存在于“FileStream”类中的函数。仔细的读者大概会注重到这句代码"openMicrosoft.FSharp.Control.CommonExtensions",它翻开了一个包括良多F#范例把持的定名空间。这个工具和C#的扩大办法很相似,同意你为现存的类增加分外的函数,而定名空间“Microsoft.FSharp.Control.CommonExtensions”为异步事情流的利用供应了良多扩大。
还必要注重的中央就是,我们仍旧利用了“use”赋值语句来烧毁文件对象,即便这意味着文件对象将会在别的一个线程中被烧毁,我们也不必太忧虑,它能一般地事情的。
其他分明的改动就是,我们怎样实行这些代码,“fileOpen”标识符不会即刻翻开文件,它只是一个事情流,一个守候实行的举措。为了实行这个举措,我们必要利用“Async.Run”函数,它会实行一个独自的事情流并守候其完成后取得实行了局。
我发明,在“ReadAsync”四周增加一些对换试函数的挪用,有助于了解异步程序是怎样实行的,它让我们可以看到程序的谁人线程正在被实行和响应的线程仓库跟踪信息,可是我盘算把这个接洽留给读者本人完成:
letprintThreadDetails()=Console.WriteLine("ThreadID{0}",Thread.CurrentThread.ManagedThreadId)Console.WriteLine((newStackTrace()).ToString())转头看一下我之前的关于事情流的文章(《超出F#基本——事情流》)也是一个进修“let!”语句的好中央,你能够看到“let!”是怎样给延续函数带来一些特别效果的。这也能够匡助你了解,异步事情流怎样在“let!”以后开启别的一个线程的。
量化功能的改良
那末,当利用异步事情流的时分我们但愿看到哪方面的功能改良呢?与年夜多半功能相干的成绩一样,在没有诉诸实验之前是很难回覆的。典范的程序不是在举行盘算就是在举行I/O处置,经由过程使用异步事情流,你一般在这两个方面都能看到功能有所提拔。不外,应当注重的是,你所利用的硬件也将对功能发生伟大的影响,假如你的义务次要举行I/O处置,那末你不会看到明显的功能提拔,除非你的磁盘供应了很好的并发会见才能,别的,就算存在一些能供应十分好的并发会见才能的磁盘,那也是共同高规格的服务器来利用,而不是用于条记本或台式机上的。假如你的义务是次要依托处置器的盘算,那末你在年夜部分古代的条记本和台式机上一般能够看到更好的功能改良,这些呆板都装备了双核处置器,而且良多读者大概已在思索为本人订购一台将要上市的四核机型了。这意味着,经由过程准确使用异步事情流,你将可以充实利用这些分外的处置器才能。
让我们来完成一个触及到I/O和盘算处置的义务例子,来看看我们取得了那品种型的功能改良。假设我们有一些但愿举行剖析的ascii文本,起首要盘算单词总数,然后盘算独一单词(即只呈现一次的单词)的数目。翻开和读取文件将触及I/O的操纵,盘算单词总数和独一单词数目会占用CPU的盘算开支。为了举行测试,我从ProjectGutenberg下载了HenryFielding的一切作品。
起首,我们来看一个同步体例剖析这些作品的剧本:
#lightopenSystemopenSystem.DiagnosticsopenSystem.IOopenSystem.Text.RegularExpressionsletpath=@"C:UsersobertDocumentsFielding"letreadFilefilePath=//openandreadfileletfileStream=File.OpenText(filePath)lettext=fileStream.ReadToEnd()//findallthe"words"usingaregexletword=newRegex("w+")letmatches=word.Matches(text)letwords={forminmatches->m.Value}//countuniquewordsusingasetletuniqueWords=Set.of_seqwords//printtheresultsletname=Path.GetFileNameWithoutExtension(filePath)Console.WriteLine("{0}-Words:{1}Uniquewords:{2}",name,matches.Count,uniqueWords.Count)letmain()=letfilePaths=Directory.GetFiles(path)forfilePathinfilePathsdoreadFilefilePath正如你所看到的如许,我们的脚步长短常直不雅的,起首我们翻开和读取文件,接着我们使用正在表达式计数一切的单词(在这里,我们界说单词为一个或多个联贯的字符),最初我们创立一个Set的实例来计数独一单词。“Set”范例是F#原生函数库中的一部分,实在现了数学中Set的模子,它是一种不成变的数据布局,能够很无效率地完成盘算文档中独一单词的事情;就算云云,CPU关于如许的盘算仍是对照敏感的。
如今,让我们来看一下异步体例的版本:
#lightopenSystemopenSystem.IOopenSystem.Text.RegularExpressionsopenMicrosoft.FSharp.Control.CommonExtensionsletpath=@"C:UsersobertDocumentsFielding"letreadFileAsyncfilePath=async{//openandreadfileletfileStream=File.OpenText(filePath)let!text=fileStream.ReadToEndAsync()//findallthe"words"usingaregexletword=newRegex("w+")letmatches=word.Matches(text)letwords={forminmatches->m.Value}//countuniquewordsusingasetletuniqueWords=Set.of_seqwords//printtheresultsletname=Path.GetFileNameWithoutExtension(filePath)doConsole.WriteLine("{0}-Words:{1}Uniquewords:{2}",name,matches.Count,uniqueWords.Count)}letmain()=letfilePaths=Directory.GetFiles(path)lettasks=Async.Run(Async.Paralleltasks)main()正如我们所看到的那样,文件读取函数举行了一点改动——除利用“async{...}”举行事情流的代码举行包装外,还用“ReadToEndAsync”来取代“ReadToEnd”对这个事情流举行挪用。在“main”函数里的改动更成心思,在这里我们起首映照我们文件的了吧到一个异步事情流的列表上,并把它赋值给一个“tasks”标识符(即变量)。记着,在此时,事情流还未实行,为了实行它们,我们利用“Async.Parallel”来把义务列表(tasks)转换为能够并行实行的一个事情流。接着,我们利用“Async.Run”来并交运行这些义务。
我在我的条记本(双核)上经由过程F#的交互界面运转这些测试,这个交互界面能够供应一些十分棒的计时工具。我的体例十分复杂:我运转两个剧本一次,并取得运转了局(如许做为了打消磁盘缓存对功能的影响),接着我再运转每一个剧本3次:
同步异步第一次运转16.80712.928第二次运转16.78113.182第三次运转16.90913.233均匀16.83213.114
因此,不必要对代码举行大批的修正,只需调剂几行代码,在双核呆板上异步版本约莫比同步版本运转快22%,当为何我们没有看到1900%的速率提拔呢?谜底长短常复杂的,这个义务不完整在举行盘算处置,假如我们增加更多的盘算事情到我们的算法内里,好比盘算每一个单词呈现的次数,大概查找相似单词,如许我们大概会看到速率提拔百分比的进步。读取和处置文件不但是异步事情流使用的一个中央,它们也能被用于收集编程。实践上,收集数据会见比磁盘会见慢很多,而利用异步事情流能够在收集会见完成之前制止堵塞线程,如许做取得的功能提拔要比会见文件要高很多。
结论
异步事情流办理了一个很详细的成绩,怎样准确地利用.NET异步编程模子,来在.NET框架中供应最文雅的办理计划。利用异步编程模子能匡助你让使用程序更具伸缩性,而异步事情流能够帮你更简单地完成如许的事情。
分外浏览
JefferyRichter在这里利用C#完成异步编程模子的过程当中,谈到了一些成绩息争决计划。
异步事情流在《初级F#》(ExpertF#)一书中的第13章有所谈及,并在第14章供应了一些例子。
检察英文原文:BeyondFoundationsofF#-AsynchronousWorkflows
来自:http://www.infoq.com/cn/articles/pickering-fsharp-async
呵呵,那你就关注微软的招聘信息以及别人的招聘经验啊,还有也不一定去做技术的,你如果真的想去就多了解了解。(其实我的意思是说想到微软做技术是很不容易的。 ASP是把代码交给VBScript解释器或Jscript解释器来解释,当然速度没有编译过的程序快了。 同时也感谢博客园给我们这个平台,也感谢博客园的编辑们做成专题引来这么多高人指点。 众所周知,Windows以易用而出名,也因此占据不少的服务器市场。 虽然在形式上JSP和ASP或PHP看上去很相似——都可以被内嵌在HTML代码中。但是,它的执行方式和ASP或PHP完全不同。在JSP被执行的时候,JSP文件被JSP解释器(JSPParser)转换成Servlet代码,然后Servlet代码被Java编译器编译成.class字节文件,这样就由生成的Servlet来对客户端应答。所以,JSP可以看做是Servlet的脚本语言(ScriptLanguage)版。 微软又推出ASP.NET。这不是ASP的简单升级,而是全新一代的动态网页实现系统,用于一台WEB服务器建立强大的应用程序。是微软发展的新体系结构.NET的一部分,是ASP和.NET技术的结合。 网页从开始简单的hmtl到复杂的服务语言,走过了10多个年头,各种技术层出不穷,单个的主流技术也在不断翻新的版本,现在分析下各种语言的区别、优势、劣势、开发注意事项! 在一个项目中谁敢保证每天几千万甚至几亿条的数据不丢失?谁敢保证应用的高可靠性?有可以借签的项目吗? ASP.Net摆脱了以前ASP使用脚本语言来编程的缺点,理论上可以使用任何编程语言包括C++,VB,JS等等,当然,最合适的编程语言还是MS为.NetFrmaework专门推出的C(读csharp)。 现在主流的网站开发语言无外乎asp、php、asp.net、jsp等。 Asp.net:首先来说,Asp.net和Asp没什么关系,看着像是升级版本什么的,其实没什么联系。Asp是脚本编程,用的是ASP语言,而ASP.net用的是C#语言,完全不同的东西。
页:
[1]