A. 何时使用 Parallel.ForEach,何时使用 PLINQ
当需要为多核机器进行优化的时候,最好先检查下你的程序是否有处理能够分割开来进行并行处理。(例如,有一个巨大的数据集合,其中的元素需要一个一个进行彼此独立的耗时计算)。.netframework4中提供了Parallel.ForEach和PLINQ来帮助我们进行并行处理,本文探讨这两者的差别及适用的场景。Parallel.ForEachParallel.ForEach是foreach的多线程实现,他们都能对IEnumerable类型对象进行遍历,Parallel.ForEach的特殊之处在于它使用多线程来执行循环体内的代码段。Parallel.ForEach最常用的形式如下:(IEnumerablesource,Actionbody)PLINQPLINQ也是一种对数据进行并行处理的编程模型,它通过LINQ的语法来实现类似Parallel.ForEach的多线程并行棚宴处理。场景一:简单数据之独立操作的并行处理(使用Parallel.ForEach)示例代码:(IEnumerablesource,Actionaction){Parallel.ForEach(source,element=>action(element));}理由:1.虽然PLINQ也提供了一个类似的ForAll接口,但它对于简单的独立操作太重量化了。2.使用Parallel.ForEach你还能够设定ParallelOptions.MaxDegreeOfParalelism参数(指定最多需要多少个线程),这样当ThreadPool资源匮乏(甚至当可用线程数Movie){varProcessedMovie=Movie.AsParallel().AsOrdered().Select(frame=>ConvertToGrayscale(frame));foreach(){//}}理由:1.Parallel.ForEach实现起来需链友银要绕一些弯路,首先你需要使用以下的重载在方法:(IEnumerablesource,Actionbody)这个重载的Action多包含了index参数,这样你在输出的时候就能利用这个值来维持原先的序列顺序。请看下面的例子:告薯publicstaticdouble[]PairwiseMultiply(double[]v1,double[]v2){varlength=Math.Min(v1.Length,v2.Lenth);double[]result=newdouble[length];Parallel.ForEach(v1,(element,loopstate,elementIndex)=>result[elementIndex]=element*v2[elementIndex]);returnresult;}你可能已经意识到这里有个明显的问题:我们使用了固定长度的数组。如果传入的是IEnumerable那么你有4个解决方案:(1)调用IEnumerable.Count()来获取数据长度,然后用这个值实例化一个固定长度的数组,然后使用上例的代码。(2);,.(没看懂贴原文)(3)第三种方式是采用返回一个哈希集合的方式,这种方式下通常需要至少2倍于传入数据的内存,所以处理大数据时请慎用。(4)自己实现排序算法(保证传入数据与传出数据经过排序后次序一致)2.相比之下PLINQ的AsOrdered方法如此简单,而且该方法能处理流式的数据,从而允许传入数据是延迟实现的(lazymaterialized)场景三:流数据之并行处理(使用PLINQ)PLINQ能输出流数据,这个特性在一下场合非常有用:1.结果集不需要是一个完整的处理完毕的数组,即:任何时间点下内存中仅保持数组中的部分信息2.你能够在一个单线程上遍历输出结果(就好像他们已经存在/处理完了)示例:publicstaticvoidAnalyzeStocks(IEnumerableStocks){varStockRiskPortfolio=Stocks.AsParallel().AsOrdered().Select(stock=>new{Stock=stock,Risk=ComputeRisk(stock)}).Where(stockRisk=>ExpensiveRiskAnalysis(stockRisk.Risk));foreach(){SomeStockComputation(stockRisk.Risk);//}}这里使用一个单线程的foreach来对PLINQ的输出进行后续处理,通常情况下foreach不需要等待PLINQ处理完所有数据就能开始运作。PLINQ也允许指定输出缓存的方式,具体可参照PLINQ的WithMergeOptions方法,及ParallelMergeOptions枚举场景四:处理两个集合(使用PLINQ)PLINQ的Zip方法提供了同时遍历两个集合并进行结合元算的方法,并且它可以与其他查询处理操作结合,实现非常复杂的机能。示例:(IEnumerablea,IEnumerableb){returna.AsParallel().AsOrdered().Select(element=>ExpensiveComputation(element)).Zip(b.AsParallel().AsOrdered().Select(element=>DifferentExpensiveComputation(element)),(a_element,b_element)=>Combine(a_element,b_element));}示例中的两个数据源能够并行处理,当双方都有一个可用元素时提供给Zip进行后续处理(Combine)。Parallel.ForEach也能实现类似的Zip处理:(IEnumerablea,IEnumerableb){varnumElements=Math.Min(a.Count(),b.Count());varresult=newT[numElements];Parallel.ForEach(a,(element,loopstate,index)=>{vara_element=ExpensiveComputation(element);varb_element=DifferentExpensiveComputation(b.ElementAt(index));result[index]=Combine(a_element,b_element);});returnresult;}当然使用Parallel.ForEach后你就得自己确认是否要维持原始序列,并且要注意数组越界访问的问题。场景五:线程局部变量Parallel.ForEach提供了一个线程局部变量的重载,定义如下:(IEnumerablesource,FunclocalInit,Funcbody,ActionlocalFinally)使用的示例:publicstaticListFiltering(IEnumerablesource){varresults=newList();using(SemaphoreSlimsem=newSemaphoreSlim(1)){Parallel.ForEach(source,()=>newList(),(element,loopstate,localStorage)=>{boolfilter=filterFunction(element);if(filter)localStorage.Add(element);returnlocalStorage;},(finalStorage)=>{lock(myLock){results.AddRange(finalStorage)};});}returnresults;}线程局部变量有什么优势呢?请看下面的例子(一个网页抓取程序):(){WebClientwebclient=newWebClient();Parallel.ForEach(urls,(url,loopstate,index)=>{webclient.DownloadFile(url,filenames[index]+".dat");Console.WriteLine("{0}:{1}",Thread.CurrentThread.ManagedThreadId,url);});}通常第一版代码是这么写的,但是运行时会报错“System.NotSupportedException->/Ooperations.”。这是因为多个线程无法同时访问同一个WebClient对象。所以我们会把WebClient对象定义到线程中来:publicstaticvoidBAD_DownloadUrls(){Parallel.ForEach(urls,(url,loopstate,index)=>{WebClientwebclient=newWebClient();webclient.DownloadFile(url,filenames[index]+".dat");Console.WriteLine("{0}:{1}",Thread.CurrentThread.ManagedThreadId,url);});}修改之后依然有问题,因为你的机器不是服务器,大量实例化的WebClient迅速达到你机器允许的虚拟连接上限数。线程局部变量可以解决这个问题:(){Parallel.ForEach(urls,()=>newWebClient(),(url,loopstate,index,webclient)=>{webclient.DownloadFile(url,filenames[index]+".dat");Console.WriteLine("{0}:{1}",Thread.CurrentThread.ManagedThreadId,url);returnwebclient;},(webclient)=>{});}这样的写法保证了我们能获得足够的WebClient实例,同时这些WebClient实例彼此隔离仅仅属于各自关联的线程。虽然PLINQ提供了ThreadLocal对象来实现类似的功能:publicstaticvoiddownloadUrl(){varwebclient=newThreadLocal(()=>newWebClient());varres=urls.AsParallel().ForAll(url=>{webclient.Value.DownloadFile(url,host[url]+".dat"));Console.WriteLine("{0}:{1}",Thread.CurrentThread.ManagedThreadId,url);});}但是请注意:ThreadLocal相对而言开销更大!场景五:退出操作(使用Parallel.ForEach)Parallel.ForEach有个重载声明如下,其中包含一个ParallelLoopState对象:(IEnumerablesource,Actionbody)ParallelLoopState.Stop()提供了退出循环的方法,这种方式要比其他两种方法更快。这个方法通知循环不要再启动执行新的迭代,并尽可能快的推出循环。ParallelLoopState.IsStopped属性可用来判定其他迭代是否调用了Stop方法。示例:publicstaticbooleanFindAny(IEnumerableTSpace,Tmatch)whereT:IEqualityComparer{varmatchFound=false;Parallel.ForEach(TSpace,(curValue,loopstate)=>{if(curValue.Equals(match)){matchFound=true;loopstate.Stop();}});returnmatchFound;}ParallelLoopState.Break()通知循环继续执行本元素前的迭代,但不执行本元素之后的迭代。最前调用Break的起作用,并被记录到ParallelLoopState.LowestBreakIteration属性中。这种处理方式通常被应用在一个有序的查找处理中,比如你有一个排序过的数组,你想在其中查找匹配元素的最小index,那么可以使用以下的代码:(IEnumerableTSpace,Tmatch)whereT:IEqualityComparer{varloopResult=Parallel.ForEach(source,(curValue,loopState,curIndex)=>{if(curValue.Equals(match)){loopState.Break();}});varmatchedIndex=loopResult.LowestBreakIteration;returnmatchedIndex.HasValue?matchedIndex:-1;}
B. 区块链技术有哪些应用
《关于深化公共资源交易平台整合共享的指导意见》(国办函〔2019〕41号)文件指出需优化见证、场所、信息、档案、专家抽取等服务。但目前公共资源交易过程见证以人工现场见证为主,见证力度有限,对人力资源占用高,见证效果有限。传统的数字化见证系统因其中心化特点事后数据容易被篡改,且数据在存储、迁移过程容易损坏或丢失,从安全性可用性上都存在一定缺陷。
利用区块链分布式、难篡改、可追溯的特点对每个交易环节产生的数据进行固化存证,通过时间戳技术、摘要算法、电子签名技术准确记录数据产生的时间、内容、数据来源。根据区块链的技术特性对于简单的结构化数据可直接将数据保存在区块链上,对于非结构化的版式文件、视频、音频的等大文件通过区块链保存其摘要信息,原文件通过分布式文件存储服务进行保存。当交易存在纠纷或者问题的时候,区块链可提供一套可信的交易过程数据,厘清交易主体各方的责任。实现全环节风险防控、全过程可溯可查、全方位服务提升的目标。
促进电子保函费率合理化
促进投标企业金融服务和企业融资
促进电子保函费率合理化
目前电子投标保证金担保保函已在招投标领域有一定的应用,为投标企业解决了投标保证金方面的资金占用问题。但因目前各家金融机构没有可靠的投标人历史投标行为数据,无法对不同投标人的违约风险进行判别,导致对投标人收取的担保服务都采用固定费率,使少部分违约风险高的投标人担保成本侍轮轮被分摊到大部分违约风险低的投标人身上,在一定程度上提高了大部分投标人保函费率。
目前是否使用电子保函由投标人自主选择,而费率又是投标人的主要选择依据,若通过区块链汇聚共享投标人履约记录,分析不同投标人履约风险,为不同投标人提供不同担保费率,既降低金融机构风险,又可降低大部分投标人的使用成本促进投标保函的使用,在一定程度上也可促进投标人重约定守信用,维护招投标市场秩序。
促进投标企业金融服务
投标人的投标行为分散在各个交易中心,单纯地将数据汇聚至一个中心化的信息系统又存在数据被篡改风险(不可信),老信有价值的投标人交易行为数据无法安全可靠地汇聚、共享。通过区块链技术汇聚多个交易中心投标人,历史投标、中标、违约、违规等行为记录为金融机构对投标人的在招投标细分行业的信用评估提供数据支撑。
解决中标企业融资问题
传统的企业贷款主要通过评估企业偿债能力:抵押物、审计过的报表、持续性盈利等有要求,但是大多桐拿数中小企业根本拿不出这些“证明”,融资难、融资贵成为招投标活动中许多中小企业面临的问题。使用过去的方法已经走不通了,要破解中小企业融资难问题,唯有依靠新技术和新工具。借助区块链不可篡改的特点,汇聚多个交易中心一手业务数据,结合大数据分析技术构建可信投标人画像。一方面提金融机构高风控水平,挖掘优质投标企业,另一方面为投标企业降低贷款门槛,优化服务体验。
借鉴供应链金融模式,招标人是政府部门、国家企事业单位具有很好信用的核心企业,中标人作为供应商获得的中标合同被金融机构认为是一种优质的资产向金融机构申请贷款。传统纸质模式下存在订单合同造假风险且流程烦琐,中心化系信息系统又需要运营方有极强的权威性。区块链的分布式账本及难篡改特点将有助于上述问题的解决,将招标人与投标人的合同签署及后续金融服务环节都在区块链上实现,既解决数据可信问题又降低了整个系统对中心化权威机构的依赖。
C. 数字货币平台开发,什么是数字货币
概念:数字货币是指对货币进行数字化
数字货币/虚拟货币既然困孙叫"货币",必定要有货币的功能才对,货币最大的功能是支付和汇率,现行的数字货币有没有这方面的功能呢,或者说计划呢?是有的,有些币种,比方NPC、Zrcoin在创世的时分是以什物财物来做背书的,这么的币具有和什物价值相关的特点,是价值的最真实体现,也是最有也许向支付运用改变的币种,币的寿数和将来的远景也是会不错的.
比特币之类的货币像莱特币、维卡币,元宝币,天元仙宝(天元币)等,是一种依靠密码技术和校验技术来创建,分发和维持的数字货币。密码货币的特点在其运用了点对点技术且每个人都有发行它。
说到数字货币就不得不提比特币的发展历史了,毕竟比特币类似于数字货币也把各种山寨币的都带动了起来!
2008年11月1日中本聪在metzdowd的密码学邮件组列表中发表了一篇论文,论文描述了比特币的电子现金系统。
2009年,不受中央和任何金融机构控制的比特币诞生。比特币用揭露散布总账摆脱了第三方机构的制约,中本聪称之为“区域链”其货币特征包括:去中心化、全世界流通、专属所有权、低交易费用、无隐藏成本、跨平台挖掘等。
2009年1月3日,中本聪制作了比特币世界的第一个区块“创世区块”。比特币的创始人中本聪在创世区块里留下一句永不可修改的话:“The Times 03/Jan/2009 Chancellor on brink of second lout for
banks(2009年1月3日,财政大臣正处于实施第二轮银行紧急援助的边缘)当时正是英国的财政大臣达林被迫考虑第二次出手纾解银行危机的时刻,这句话是泰晤士报当天的头版文章标题。
2010年5月21日,佛罗里达程序员用1万比特币购买了价值25美元的披萨优惠券,随着这笔交易诞生了比特币第一个公允汇率。
2010年7月,第一个比特币平台成立,新用户暴增,价格暴涨。
2011年2月,比特币价源尺早格首次达到1美元,此后与英镑、巴西雷亚尔、波兰兹罗提汇兑交易平台开张。
2012年,瑞波发布,其作为数字货币,利用区块链转移各国外汇。
2013年,比特币暴涨。美国财政部发布了虚拟货币个人管理条例,首次阐明虚拟货币释义。
2014年,以中国为代表的矿机产业链日益成熟,同年,美国IT界认识到区块链对于数字领域的跨时代创新意义。
2014年,央行成立专门研究团队,并于2015年初进一步充实力量,对数字货币发行和业务运行框架、数字货币的关键技术等进行了深入研究,已取得阶段性成果。
2014年3月9日上午,谷歌创意主管杰雷德·科恩(Jared Cohen)本周在参加SXSW大会时表示,与比特币类似的数字加密货币将长期存在。科恩和谷歌董事长埃里克·施密特(Eric Schmidt)在此次大会上推广了合著的《新数字时代》一书。
2014年7月,中国国务院颁布了《关于积极推进“互联网+”行动的指导意见》把“互联网+”列入“十三五”雹雀规划产业的发展主线,提出拓展网络经济空间,发展分享经济,促进互联网和经济社会融合发展。实施国家大数据战略,推进数据资源开放共享。
2015年英国首先提出将“沙盒”这一理念应用到金融监管领域,为创新企业提供了缩小版的真实环境。建立沙盒机制能让政府在可控的范围内进行多种创新,给区块链行业带来更多机会。
2015年11月,纳斯达克和Chain合作的区块链技术新项目Linq以利于基于区块链的发行交易平台完成了第一笔私募股权交易。
2015年12月,美国纳斯达克首次在个股交易商使用区块链技术。
2015年年末,以R3CEV为代表的区块链联盟成立,短时间内吸引了超过40家国际银行业巨头加盟。
2016年是“区块链元年”。各路风投投入了上十亿美金资金投入到区块链的创业公司和项目,这一年区块链价值被全世界认可,区块链概念被不断验证。
2016年1月中国人民银行数字货币研讨会在北京召开,进一步明确央行发行数字货币的战略目标,做好关键技术攻关,研究数字货币的多场景应用,争取早日推出央行发行的数字货币。未来的数字货币可能在区块链上建立账本,不会被人篡改,而电子支付只是单向记账。越来越多的金融机构开始关注数字货币背后的创新技术——“区块链(blockchain)”。
2016年10月,工信部发布《中国区块链技术和应用发展白皮书》,这是首个落地的区块链官方指导文件。年末,国务院印发《“十三五”国家信息化规划》,区块链与大数据、人工智能、机器深度学习等新技术,成为国家布局重点。区块链技术可能重塑政府运行方式,并使其变得更高效。在政府信任度降低的时代,信息必须以更加透明和负责的方式进行存储。区块链为政府在治理、安全和法律领域提供了多种可能性。
2016年12月, 浙商银行也正式上线基于区块链技术移动数字汇票产品,搭建了基于区块链技术移动数字汇票平台。
2016年12月15日,央行数字票据基于区块链的全生命周期的登记流转和基于数字货币的票款对付(DVP)结算功能已经全部实现,显示数字货币在数字票据场景的应用验证落地。
2017年,区块链技术将突破实验室并进入真实的市场环境。
2017年7月1日,上海第一家无人超市落地,24小时营业,没有一个员工
2017年1月10日,中国邮政储蓄银行和IBM联合宣布推出基于区块链的资产托管系统,该系统于2016年10月上线,已在真实业务环境中顺利执行了上百笔交易。这是中国银行业将区块链技术应用于银行核心业务系统的首次成功实践。
2017年1月25日,中国央行推动的基于区块链的数字票据交易平台已测试成功。
(银行相争涌入区块链领域的原因很简单,银行通过使用自己许可式区块链来记录所有客户交易,提高交易效率,不用再把交易数据记录到各种不同类型并且很快过时的软件中。)
2017年7月2日,深圳实现自动收银,全程再无收银员
2017年7月7日到8日,于汉堡举行的二十国集团首脑峰会上普金表示,数字技术的发展将为全球经济向新的工业秩序转型提供支撑。
这不得不提到区块链技术了!比特币这几年火了,估计中本聪也没想到比特币竟然这么贵,09年出来的比特币,现在17年的比特币接近2万元/1个,发展之快和价值之高,简直难以想象。这让我想起了当年用10000个比特币购买20多美元的披萨,真不愧是世界上最贵的交易,也许在当时不值钱,如果用现在的计算方式你会震惊!一万个比特币*现在价格两万/一个,猜猜多少?……
算出来了吗?当时也把我吓住了,没错,接近2个亿,的确是最贵的披萨,这一般人享受不起啊,/汗!颜/。比特币之类的币种发展速度之快,真的超乎想象!(如果需要数字货币开发区块链交易所系统可以找我)
那我为什么说不得不提到区块链技术呢?区块链作为比特币的底层核心技术,它的应用价值比比特币更高,相当于在比特币中,金矿-矿工-矿车,它相当于矿车,说的简单点,金矿好比资产的,对于矿工来说就是从一个地方运到另一个地方,矿工要维持金矿的运转肯定会挖矿,但是矿车呢?矿车除了运金矿,还有很多功能,他可以做其他很多领域的事情,这些都可以用区块链技术。区块链就像一个数据库账本,记载所有的交易记录。
把区块链想象成一个比特币的公共账本,这个账本:
1.存放在互联网的各个比特币节点上,每个节点都有一份完整的备份
2.里面记录着自比特币诞生以来的所有比特币转账交易
3.账本是分区块存储的,每一块包含一部分交易记录。每一个区块都会记录着前一区块的id,形成一个链状结构,因而称为区块链
4.当你要发起一笔比特币交易的时候只需把交易信息广播到p2p网络中,矿工把你的交易信息记录成一个新的区块连到区块链上,交易就完成了。
由中本聪提出的数字货币和区块链到现在为止已经进入了爆发式的增长,那么区块链技术能应用到哪些领域呢?
涉及资产领域,无论是房产、汽车等实物资产,还是健康、名誉等无形资产,都能利用该技术完成登记、交易、追踪。可以这样说,任何缺乏信任的生产生活领域,区块链交易所技术都将有用武之地。
随着区块链技术在中国的发展,在商业机构、政府和用户的共同推动下,已逐渐形成一个交易、监管不断优化的区块链环境。致力于区块链技术研究和应用的企业和个人将会有更多的财富机会去创造更大的商业价值,实现区块链技术理念的美好前景。
关于数字货币的将来,推动数字货币开展,数字货币创业者,出资者和极客供给最具有价值工作前沿资讯,在这里将造就不计其数的百万、千万、亿万富翁,当金融遇上互联网,再加上复利倍增方式,财富将超越你的梦想。(对数字货币比特币交易所感兴趣的可以加我微QKL17999/q+2729656186/电+13823153926)
D. c# 大数据量问题
3000条数据,不脊斗态是3000万条,不用考销宏虑得这么精细。
更何况,就算是3000万条,也不过是几十秒的时间,一般从数据库读取到展示,如果是3000万条的话,也要这么多时间的,如樱源果电脑配置更加低的话,更久。
所以foreach+foreach也没什么,3000条,一秒内就完了。
E. linq to sql 和entity framework 相比,哪个性能更好
单从实现方式上来讲应该是entity framework效率更高,虽然我从没用过,也很少使用linq,entity framework是一套orm框架,类似的还有很慧信多,而linq to sql 是在orm的基础上再去使用linq特橡睁性实现某个功能,相对基础语法,linq的使用只是减少了代码,却影响了性能。所以梁碧岁我认为linq to sql性能会差一些。但是,这也取决于两套东西内部具体的实现和应用,尤其应用在大数据量的场景中才能比较出差异。各有优劣,这样看来这个提问有点过于笼统了哦。 所以具体的应用还要看具体的需求,单独讲性能的话还是基础语法来的最快。
F. C#:在类的静态方法代码中能否使用this对象引用,为什么
this指的是类实碰老例化的当前对象,静态方法是通过类调用的,不需要实例化;既然不需要实例化,就没有当前对象;罩衫既然没有当前对象,所以不能使用this 关键字。
C#四种用法:
用法一 this代表当前类的实例对象
用法二 用this串联构造函数
用法三 为原始类型物吵腔扩展方法
用法四 索引器(基于索引器封装EPList,用于优化大数据下频发的Linq查询引发的程序性能问题,通过索引从list集合中查询数据)
G. asp.net mvc linq 查询 出现类型不能强制转换,怎么解决
如果数据列中没有图片流等大数据,你就老老实枣埋实用m就行,如果你想只选择出必要的列,可以在御虚select的时候new Movie出来并只填充要选择的列凳拆蚂,或者 自定义一个ViewModel 。
H. 何时使用 Parallel.ForEach,何时使用 PLINQ
当需要为多核机器肆磨进行优化的时候,最好先检查下你的程序是否有处理能够分割开来进行并行处理。(物弯例如,有一个巨大的数据集合,其中的元素需要一个一个进行彼此独立的耗时计算)。
.net framework 4 中提供了 Parallel.ForEach 和 PLINQ 来帮助我们进行并行处理,本文探讨这两者的差别及适用的场景。
Parallel.ForEach
Parallel.ForEach 是 foreach 的多线程实现,他们都能对 IEnumerable<T> 类型对象进行遍历,Parallel.ForEach 的特殊之处在于它使用多线程来执行循环体内的代码段。
Parallel.ForEach 最常用的形式如下:
public static ParallelLoopResult ForEach<TSource>(
IEnumerable<TSource> source,
Action<TSource> body)
PLINQ
PLINQ 也是一种对数据进行并行处理的编程模型,它通过 LINQ 的语法来实现类似 Parallel.ForEach 的多线程并行处理。
场景一:简单数据 之 独立操作的并行处理(使用 Parallel.ForEach)
示例代码:
public static void IndependentAction(IEnumerable<T> source, Action<T> action)
{
Parallel.ForEach(source, element => action(element));
}
理由:
1. 虽然 PLINQ 也提供了一个类似的 ForAll 接口,但它对于简单的独立操作太重量化了。
2. 使用 Parallel.ForEach 你还能够设定
ParallelOptions.MaxDegreeOfParalelism 参数(指定最多需要多少个线程),这样当 ThreadPool
资源匮乏(甚至当可用线程数<MaxDegreeOfParalelism)的时候, Parallel.ForEach
依然能够顺利运行,并且当后续有更多可用线程出现时,Parallel.ForEach 也能及时地利用这些线程。PLINQ
只能通过WithDegreeOfParallelism 方法来要求固定的线程数,即:要求了几个就是几个,不会多也不会少。
场景二:顺序数据 之 并行处理(使用 PLINQ 来维持数据顺序)
当输出的数据序列需要保裂蚂斗持原始的顺序时采用 PLINQ 的 AsOrdered 方法非常简单高效。
示例代码:
public static void GrayscaleTransformation(IEnumerable<Frame> Movie)
{
var ProcessedMovie =
Movie
.AsParallel()
.AsOrdered()
.Select(frame => ConvertToGrayscale(frame));
foreach (var grayscaleFrame in ProcessedMovie)
{
// Movie frames will be evaluated lazily
}
}
理由:
1. Parallel.ForEach 实现起来需要绕一些弯路,首先你需要使用以下的重载在方法:
public static ParallelLoopResult ForEach<TSource >(
IEnumerable<TSource> source,
Action<TSource, ParallelLoopState, Int64> body)
这个重载的 Action 多包含了 index 参数,这样你在输出的时候就能利用这个值来维持原先的序列顺序。请看下面的例子: public static double [] PairwiseMultiply(double[] v1, double[] v2)
{
var length = Math.Min(v1.Length, v2.Lenth);
double[] result = new double[length];
Parallel.ForEach(v1, (element, loopstate, elementIndex) =>
result[elementIndex] = element * v2[elementIndex]);
return result;
}
你可能已经意识到这里有个明显的问题:我们使用了固定长度的数组。如果传入的是 IEnumerable 那么你有4个解决方案:
(1) 调用 IEnumerable.Count() 来获取数据长度,然后用这个值实例化一个固定长度的数组,然后使用上例的代码。
(2) The second option would be to materialize the original
collection before using it; in the event that your input data set is
prohibitively large, neither of the first two options will be
feasible.(没看懂贴原文)
(3) 第三种方式是采用返回一个哈希集合的方式,这种方式下通常需要至少2倍于传入数据的内存,所以处理大数据时请慎用。
(4) 自己实现排序算法(保证传入数据与传出数据经过排序后次序一致)
2. 相比之下 PLINQ 的 AsOrdered 方法如此简单,而且该方法能处理流式的数据,从而允许传入数据是延迟实现的(lazy materialized)
场景三:流数据 之 并行处理(使用 PLINQ)
PLINQ 能输出流数据,这个特性在一下场合非常有用:
1. 结果集不需要是一个完整的处理完毕的数组,即:任何时间点下内存中仅保持数组中的部分信息
2. 你能够在一个单线程上遍历输出结果(就好像他们已经存在/处理完了)
示例:
public static void AnalyzeStocks(IEnumerable<Stock> Stocks)
{
var StockRiskPortfolio =
Stocks
.AsParallel()
.AsOrdered()
.Select(stock => new { Stock = stock, Risk = ComputeRisk(stock)})
.Where(stockRisk => ExpensiveRiskAnalysis(stockRisk.Risk));
foreach (var stockRisk in StockRiskPortfolio)
{
SomeStockComputation(stockRisk.Risk);
// StockRiskPortfolio will be a stream of results
}
}
这里使用一个单线程的 foreach 来对 PLINQ 的输出进行后续处理,通常情况下 foreach 不需要等待 PLINQ 处理完所有数据就能开始运作。
PLINQ 也允许指定输出缓存的方式,具体可参照 PLINQ 的 WithMergeOptions 方法,及 ParallelMergeOptions 枚举
场景四:处理两个集合(使用 PLINQ)
PLINQ 的 Zip 方法提供了同时遍历两个集合并进行结合元算的方法,并且它可以与其他查询处理操作结合,实现非常复杂的机能。
示例:
public static IEnumerable<T> Zipping<T>(IEnumerable<T> a, IEnumerable<T> b)
{
return
a
.AsParallel()
.AsOrdered()
.Select(element => ExpensiveComputation(element))
.Zip(
b
.AsParallel()
.AsOrdered()
.Select(element => DifferentExpensiveComputation(element)),
(a_element, b_element) => Combine(a_element,b_element));
}
示例中的两个数据源能够并行处理,当双方都有一个可用元素时提供给 Zip 进行后续处理(Combine)。
Parallel.ForEach 也能实现类似的 Zip 处理:
public static IEnumerable<T> Zipping<T>(IEnumerable<T> a, IEnumerable<T> b)
{
var numElements = Math.Min(a.Count(), b.Count());
var result = new T[numElements];
Parallel.ForEach(a,
(element, loopstate, index) =>
{
var a_element = ExpensiveComputation(element);
var b_element = DifferentExpensiveComputation(b.ElementAt(index));
result[index] = Combine(a_element, b_element);
});
return result;
}
当然使用 Parallel.ForEach 后你就得自己确认是否要维持原始序列,并且要注意数组越界访问的问题。
场景五:线程局部变量
Parallel.ForEach 提供了一个线程局部变量的重载,定义如下:
public static ParallelLoopResult ForEach<TSource, TLocal>(
IEnumerable<TSource> source,
Func<TLocal> localInit,
Func<TSource, ParallelLoopState, TLocal,TLocal> body,
Action<TLocal> localFinally)
使用的示例: public static List<R> Filtering<T,R>(IEnumerable<T> source)
{
var results = new List<R>();
using (SemaphoreSlim sem = new SemaphoreSlim(1))
{
Parallel.ForEach(source,
() => new List<R>(),
(element, loopstate, localStorage) =>
{
bool filter = filterFunction(element);
if (filter)
localStorage.Add(element);
return localStorage;
},
(finalStorage) =>
{
lock(myLock)
{
results.AddRange(finalStorage)
};
});
}
return results;
}
线程局部变量有什么优势呢?请看下面的例子(一个网页抓取程序): public static void UnsafeDownloadUrls ()
{
WebClient webclient = new WebClient();
Parallel.ForEach(urls,
(url,loopstate,index) =>
{
webclient.DownloadFile(url, filenames[index] + ".dat");
Console.WriteLine("{0}:{1}", Thread.CurrentThread.ManagedThreadId, url);
});
}
通常第一版代码是这么写的,但是运行时会报错“System.NotSupportedException -> WebClient
does not support concurrent I/O operations.”。这是因为多个线程无法同时访问同一个 WebClient
对象。所以我们会把 WebClient 对象定义到线程中来: public static void BAD_DownloadUrls ()
{
Parallel.ForEach(urls,
(url,loopstate,index) =>
{
WebClient webclient = new WebClient();
webclient.DownloadFile(url, filenames[index] + ".dat");
Console.WriteLine("{0}:{1}", Thread.CurrentThread.ManagedThreadId, url);
});
}
修改之后依然有问题,因为你的机器不是服务器,大量实例化的 WebClient 迅速达到你机器允许的虚拟连接上限数。线程局部变量可以解决这个问题: public static void downloadUrlsSafe()
{
Parallel.ForEach(urls,
() => new WebClient(),
(url, loopstate, index, webclient) =>
{
webclient.DownloadFile(url, filenames[index]+".dat");
Console.WriteLine("{0}:{1}", Thread.CurrentThread.ManagedThreadId, url);
return webclient;
},
(webclient) => { });
}
这样的写法保证了我们能获得足够的 WebClient 实例,同时这些 WebClient 实例彼此隔离仅仅属于各自关联的线程。
虽然 PLINQ 提供了 ThreadLocal<T> 对象来实现类似的功能:
public static void downloadUrl()
{
var webclient = new ThreadLocal<WebClient>(()=> new WebClient ());
var res =
urls
.AsParallel()
.ForAll(
url =>
{
webclient.Value.DownloadFile(url, host[url] +".dat"));
Console.WriteLine("{0}:{1}", Thread.CurrentThread.ManagedThreadId, url);
});
}
但是请注意:ThreadLocal<T> 相对而言开销更大!
场景五:退出操作 (使用 Parallel.ForEach)
Parallel.ForEach 有个重载声明如下,其中包含一个 ParallelLoopState 对象:
public static ParallelLoopResult ForEach<TSource >(
IEnumerable<TSource> source,
Action<TSource, ParallelLoopState> body)
ParallelLoopState.Stop() 提供了退出循环的方法,这种方式要比其他两种方法更快。这个方法通知循环不要再启动执行新的迭代,并尽可能快的推出循环。
ParallelLoopState.IsStopped 属性可用来判定其他迭代是否调用了 Stop 方法。
示例:
public static boolean FindAny<T,T>(IEnumerable<T> TSpace, T match) where T: IEqualityComparer<T>
{
var matchFound = false;
Parallel.ForEach(TSpace,
(curValue, loopstate) =>
{
if (curValue.Equals(match) )
{
matchFound = true;
loopstate.Stop();
}
});
return matchFound;
}
ParallelLoopState.Break() 通知循环继续执行本元素前的迭代,但不执行本元素之后的迭代。最前调用 Break
的起作用,并被记录到 ParallelLoopState.LowestBreakIteration
属性中。这种处理方式通常被应用在一个有序的查找处理中,比如你有一个排序过的数组,你想在其中查找匹配元素的最小
index,那么可以使用以下的代码:
public static int FindLowestIndex<T,T>(IEnumerable<T> TSpace, T match) where T: IEqualityComparer<T>
{
var loopResult = Parallel.ForEach(source,
(curValue, loopState, curIndex) =>
{
if (curValue.Equals(match))
{
loopState.Break();
}
});
var matchedIndex = loopResult.LowestBreakIteration;
return matchedIndex.HasValue ? matchedIndex : -1;
}
I. 如何把linq查询结果赋值给hashset c
类似的问题被提了很多遍了,你可以从根子上这样看:
HashSet<T>的构造方法之一是HashSet<T>(IEnumerable<T> collection),这说明哈希集可以在构造时通过传入一个有着*元素类型为T的可枚举的集合*完成初始化。
如1楼所示,List<string> _dd其实本身就继承有IEnumerable<string>接口,所以不要使颤渗用Linq的cast系列方法,你只需要一行:
1
HashSet<string> _ss=new HashSet<string>(_dd);
大多数的集合类型都可以这样通过构造来初枯洞销始化。
由于这种转换是结构上的转换而非值的转换,所以绝大多数情况下都没游需要new一下目标对象,指望List<T>自己提供转换结构的方法是不靠谱的。
此外要说一句,你说的“地球人都知道”没有错,但是它还真的不慢哟。要知道,即使是使用上述构造方法,本质上来说CLR也是通过一个一个枚举_dd的元素并添加到_ss去的,两种方法在代码量上有差距,但是执行效率上几乎相等的。(因为编译时代码会自动优化的)
真的要使用大数据(如含有10万string的List<string>),请勿使用上述两种方法(因为都慢),你需要学习Parallel系列的并行处理,可以理解为一种能够利用到所有CPU核心的多线程处理。