一切福田,不離方寸,從心而覓,感無不通。

Category Archives: Programming Language

5天玩转C#并行和多线程编程 —— 第一天 认识Parallel

随着多核时代的到来,并行开发越来越展示出它的强大威力!使用并行程序,充分的利用系统资源,提高程序的性能。在.net 4.0中,微软给我们提供了一个新的命名空间:System.Threading.Tasks。这里面有很多关于并行开发的东西,今天第一篇就介绍下最基础,最简单的——认识和使用Parallel。   一、 Parallel的使用 在Parallel下面有三个常用的方法invoke,For和ForEach。   1、  Parallel.Invoke 这是最简单,最简洁的将串行的代码并行化。 在这里先讲一个知识点,就是StopWatch的使用,最近有一些人说找不到StopWatch,StopWatch到底是什么东西,今天就来说明一下。 StopWatch在System.Diagnostics命名控件,要使用它就要先引用这个命名空间。 其使用方法如下: var stopWatch = new StopWatch();   //创建一个Stopwatch实例 stopWatch.Start();   //开始计时 stopWatch.Stop();   //停止计时 stopWatch.Reset();  //重置StopWatch stopWatch.Restart(); //重新启动被停止的StopWatch stopWatch.ElapsedMilliseconds //获取stopWatch从开始到现在的时间差,单位是毫秒 本次用到的就这么多知识点,想了解更多关于StopWatch的,去百度一下吧,网上有很多资料。   下面进入整体,开始介绍Parallel.Invoke方法,废话不多说了,首先新建一个控制台程序,添加一个类,代码如下:

代码很简单,首先新加一个类,在类中写了两个方法,Run1和Run2,分别等待一定时间,输出一条信息,然后写了一个测试方法ParallelInvokeMethod,分别用两种方法调用Run1和Run2,然后在main方法中调用,下面来看一下运行时间如何: 大家应该能够猜到,正常调用的话应该是5秒多,而Parallel.Invoke方法调用用了只有3秒,也就是耗时最长的那个方法,可以看出方法是并行执行的,执行效率提高了很多。   2、Parallel.For 这个方法和For循环的功能相似,下面就在类中添加一个方法来测试一下吧。代码如下:

写了两个循环,做了一些没有意义的事情,目的主要是为了消耗CPU时间,同理在main方法中调用,运行结果如下图: 可以看到,Parallel.For所用的时间比单纯的for快了1秒多,可见提升的性能是非常可观的。那么,是不是Parallel.For在任何时候都比for要快呢?答案当然是“不是”,要不然微软还留着for干嘛? 下面修改一下代码,添加一个全局变量num,代码如下:

Parallel.For由于是并行运行的,所以会同时访问全局变量num,为了得到正确的结果,要使用lock,此时来看看运行结果: 是不是大吃一惊啊?Parallel.For竟然用了15秒多,而for跟之前的差不多。这主要是由于并行同时访问全局变量,会出现资源争夺,大多数时间消耗在了资源等待上面。 一直说并行,那么从哪里可以看出来Parallel.For是并行执行的呢?下面来写个测试代码:

从0输出到99,运行后会发现输出的顺序不对,用for顺序肯定是对的,并行同时执行,所以会出现输出顺序不同的情况。   2、Parallel.Foreach 这个方法跟Foreach方法很相似,想具体了解的,可以百度些资料看看,这里就不多说了,下面给出其使用方法:

   二、 Parallel中途退出循环和异常处理 1、当我们使用到Parallel,必然是处理一些比较耗时的操作,当然也很耗CPU和内存,如果我们中途向停止,怎么办呢? 在串行代码中我们break一下就搞定了,但是并行就不是这么简单了,不过没关系,在并行循环的委托参数中提供了一个ParallelLoopState, 该实例提供了Break和Stop方法来帮我们实现。 Break: 当然这个是通知并行计算尽快的退出循环,比如并行计算正在迭代100,那么break后程序还会迭代所有小于100的。 Stop:这个就不一样了,比如正在迭代100突然遇到stop,那它啥也不管了,直接退出。 下面来写一段代码测试一下:

这里使用的是Stop,当数量达到300个时,会立刻停止;可以看到结果"Bag count is 300",如果用break,可能结果是300多个或者300个,大家可以测试一下。   2、异常处理 首先任务是并行计算的,处理过程中可能会产生n多的异常,那么如何来获取到这些异常呢?普通的Exception并不能获取到异常,然而为并行诞生的AggregateExcepation就可以获取到一组异常。 这里我们修改Parallel.Invoke的代码,修改后代码如下:

顺序调用方法我把异常处理写一起了,这样只能捕获Run1的异常信息,大家可以分开写。捕获AggregateException 异常后,用foreach循环遍历输出异常信息,可以看到两个异常信息都显示了。   点击这里,下载源码 from:http://www.cnblogs.com/yunfeifei/p/3993401.html

龙生   13 Sep 2016
View Details

C#中小数点后保留两位小数,四舍五入的函数及使用方法

Math.Round(45.367,2)     //Returns   45.37 Math.Round(45.365,2)     //Returns   45.36 C#中的Round()不是我们中国人理解的四舍五入,是老外的四舍五入,是符合IEEE标准的四舍五入,具体是四舍六入,下面的才是符合中国人理解的四舍五入 Math.Round(45.367,2,MidpointRounding.AwayFromZero);//45.37 Math.Round(45.365,2,MidpointRounding.AwayFromZero)     //Returns   45.37   from:http://www.cnblogs.com/purplefox2008/archive/2011/08/08/2130635.html

龙生   12 Sep 2016
View Details

C#中的线程(三) 使用多线程

第三部分:使用多线程   1.  单元模式和Windows Forms 单元模式线程是一个自动线程安全机制, 非常贴近于COM——Microsoft的遗留下的组件对象模型。尽管.NET最大地放弃摆脱了遗留下的模型,但很多时候它也会突然出现,这是因为有必要与旧的API 进行通信。单元模式线程与Windows Forms最相关,因为大多Windows Forms使用或包装了长期存在的Win32 API——连同它的单元传统。 单元是多线程的逻辑上的“容器”,单元产生两种容量——“单的”和“多的”。单线 程单元只包含一个线程;多线程单元可以包含任何数量的线程。单线程模式更普遍 并且能与两者有互操作性。 就像包含线程一样,单元也包含对象,当对象在一个单元内被创建后,在它的生命周期中它将一直存在在那,永远也“居家不出”地与那些驻留线程在一起。这类似于被包含在.NET 同步环境中 ,除了同步环境中没有自己的或包含线程。任何线程可以访问在任何同步环境中的对象 ——在排它锁的控制中。但是单元内的对象只有单元内的线程才可以访问。 想象一个图书馆,每本书都象征着一个对象;借出书是不被允许的,书都在图书馆 创建并直到它寿终正寝。此外,我们用一个人来象征一个线程。 一个同步内容的图书馆允许任何人进入,同时同一时刻只允许一个人进入,在图书馆外会形成队列。 单元模式的图书馆有常驻维护人员——对于单线程模式的图书馆有一个图书管理员, 对于多线程模式的图书馆则有一个团队的管理员。没人被允许除了隶属与维护人员的人 ——资助人想要完成研究就必须给图书管理员发信号,然后告诉管理员去做工作!给管理员发信号被称为调度编组——资助人通过调度把方法依次读出给一个隶属管理员的人(或,某个隶属管理员的人!)。 调度编组是自动的,在Windows Forms通过信息泵被实现在库结尾。这就是操作系统经常检查键盘和鼠标的机制。如果信息到达的太快了,以致不能被处理,它们将形成消息队列,所以它们可以以它们到达的顺序被处理。   1.1  定义单元模式   .NET线程在进入单元核心Win32或旧的COM代码前自动地给单元赋值,它被默认地指定为多线程单元模式,除非需要一个单线程单元模式,就像下面的一样: 1 2 Thread t = new Thread (…); t.SetApartmentState (ApartmentState.STA); 你也可以用STAThread特性标在主线程上来让它与单线程单元相结合: 1 2 3 4 class Program {   [STAThread] static void Main() {   … 线程单元设置对纯.NET代码没有效果,换言之,即使两个线程都有STA 的单元状态,也可以被相同的对象同时调用相同的方法,就没有自动的信号编组或锁定发生了, 只有在执行非托管的代码时,这才会发生。 在System.Windows.Forms名称空间下的类型,广泛地调用Win32代码, 在单线程单元下工作。由于这个原因,一个Windos Forms程序应该在它的主方法上贴上 [STAThread]特性,除非在执行Win32 UI代码之前以下二者之一发生了: 它将调度编组成一个单线程单元 它将崩溃   1.2  Control.Invoke   在多线程的Windows Forms程序中,通过非创建控件的线程调用控件的的属性和方法是非法的。所有跨进程的调用必须被明确地排列至创建控件的线程中(通常为主线程),利用Control.Invoke 或 Control.BeginInvoke方法。你不能依赖自动调度编组因为它发生的太晚了,仅当执行刚好进入了非托管的代码它才发生,而.NET已有足够的时间来运行“错误的”线程代码,那些非线程安全的代码。 一个优秀的管理Windows Forms程序的方案是使用BackgroundWorker, 这个类包装了需要报道进度和完成度的工作线程,并自动地调用Control.Invoke方法作为需要。   1.3  BackgroundWorker   BackgroundWorker是一个在System.ComponentModel命名空间 下帮助类,它管理着工作线程。它提供了以下特性: "cancel" 标记,对于给工作线程打信号让它结束而没有使用 Abort的情况 提供报道进度,完成度和退出的标准方案 实现了IComponent接口,允许它参与Visual Studio设计器 […]

龙生   11 Sep 2016
View Details

C#中的线程(二) 线程同步基础

1.同步要领   下面的表格列展了.NET对协调或同步线程动作的可用的工具:                       简易阻止方法 构成 目的 Sleep 阻止给定的时间周期 Join 等待另一个线程完成                       锁系统 构成 目的 跨进程? 速度 lock 确保只有一个线程访问某个资源或某段代码。 否 快 Mutex 确保只有一个线程访问某个资源或某段代码。可被用于防止一个程序的多个实例同时运行。 是 中等 Semaphore 确保不超过指定数目的线程访问某个资源或某段代码。 是 中等 (同步的情况下也提够自动锁。)                      信号系统 构成 目的 跨进程? 速度 EventWaitHandle 允许线程等待直到它受到了另一个线程发出信号。 是 中等 Wait 和 Pulse* 允许一个线程等待直到自定义阻止条件得到满足。 否 中等                          非阻止同步系统* 构成 目的 跨进程? 速度 Interlocked* 完成简单的非阻止原子操作。 是(内存共享情况下) 非常快 volatile* 允许安全的非阻止在锁之外使用个别字段。 非常快 * 代表页面将转到第四部分 1.1   阻止 (Blocking) 当一个线程通过上面所列的方式处于等待或暂停的状态,被称为被阻止。一旦被阻止,线程立刻放弃它被分配的 CPU时间,将它的ThreadState属性添加为WaitSleepJoin状态,不在安排时间直到停止阻止。停止阻止在任意四种 情况下发生(关掉电脑的电源可不算!): 阻止的条件已得到满足 操作超时(如果timeout被指定了) 通过Thread.Interrupt中断了 通过Thread.Abort放弃了 当线程通过(不建议)Suspend 方法暂停,不认为是被阻止了。 1.2  休眠 和 轮询 调用Thread.Sleep阻止当前的线程指定的时间(或者直到中断): 1 2 3 4 5 6 static void […]

龙生   11 Sep 2016
View Details

C#中的线程(一)入门

文章系参考转载,英文原文网址请参考:http://www.albahari.com/threading/ 作者 Joseph Albahari,  翻译 Swanky Wu 中文翻译作者把原文放在了"google 协作"上面,GFW屏蔽,不能访问和查看,因此我根据译文和英文原版整理转载到园子里面。 本系列文章可以算是一本很出色的C#线程手册,思路清晰,要点都有介绍,看了后对C#的线程及同步等有了更深入的理解。 入门 概述与概念 创建和开始使用多线程 线程同步基础 同步要领 锁和线程安全 Interrupt 和 Abort 线程状态 等待句柄 同步环境 使用多线程 单元模式和Windows Forms BackgroundWorker类 ReaderWriterLock类 线程池 异步委托 计时器 局部储存 高级话题 非阻止同步 Wait和Pulse Suspend和Resume 终止线程 一、入门 1.     概述与概念 C#支持通过多线程并行地执行代码,一个线程有它独立的执行路径,能够与其它的线程同时地运行。一个C#程序开始于一个单线程,这个单线程是被CLR和操作系统(也称为“主线程”)自动创建的,并具有多线程创建额外的线程。这里的一个简单的例子及其输出: 除非被指定,否则所有的例子都假定以下命名空间被引用了:  using System; using System.Threading; 1 2 3 4 5 6 7 8 9 10 11 class ThreadTest {   static void Main() {     Thread t = new Thread (WriteY);     t.Start();                          // Run WriteY on the new thread     while (true) Console.Write ("x");   // Write 'x' forever   }     static […]

龙生   11 Sep 2016
View Details

5天玩转C#并行和多线程编程 —— 第五天 多线程编程大总结

一、多线程带来的问题 1、死锁问题 前面我们学习了Task的使用方法,其中Task的等待机制让我们瞬间爱上了它,但是如果我们在调用Task.WaitAll方法等待所有线程时,如果有一个Task一直不返回,会出现什么情况呢?当然,如果我们不做出来的话,程序会一直等待下去,那么因为这一个Task的死锁,导致其他的任务也无法正常提交,整个程序"死"在那里。下面我们来写一段代码,来看一下死锁的情况:

  这里我们创建两个Task,t1和t2,t1里面有个while循环,由于条件一直为TRUE,所以他永远也无法退出。运行程序,结果如下: 可以看到Task2完成了,就是迟迟等不到Task1,这个时候我们按回车是没有反应的,除非关掉窗口。如果我们在项目中遇到这种情况是令人很纠结的,因为我们也不知道到底发生了什么,程序就是停在那里,也不报错,也不继续执行。 那么出现这种情况我们该怎么处理呢?我们可以设置最大等待时间,如果超过了等待时间,就不再等待,下面我们来修改代码,设置最大等待时间为5秒(项目中可以根据实际情况设置),如果超过5秒就输出哪个任务出错了,代码如下:

  这里我们将所有任务放到一个数组里面进行管理,调用Task.WaitAll的一个重载方法,第一个参数是Task[]数据,第二个参数是最大等待时间,单位是毫秒,这里我们设置为5000及等待5秒钟,就继续向下执行。下面我们遍历Task数组,通过Status属性判断哪些Task没有完成,然后输出错误信息。 2、SpinLock(自旋锁) 我们初识多线程或者多任务时,第一个想到的同步方法就是使用lock或者Monitor,然而在4.0 之后微软给我们提供了另一把利器——spinLock,它比重量级别的Monitor具有更小的性能开销,它的用法跟Monitor很相似,VS给的提示如下: 下面我们来写一个例子看一下,代码如下(关于lock和Monitor的用法就不再细说了,网上资料很多,大家可以看看):

  输出结果如图: 这里我们使用了Parallel.For方法来做演示,Parallel.For用起来方便,但是在实际开发中还是尽量少用,因为它的不可控性太高,有点简单粗暴的感觉,可能带来一些不必要的"麻烦",最好还是使用Task,因为Task的可控性较好。 slock.Enter方法,解释如下: 3、多线程之间的数据同步 多线程间的同步,在用thread的时候,我们常用的有lock和Monitor,上面刚刚介绍了.Net4.0中一个新的锁——SpinLock(自旋锁),实际上,我们还可以将任务分成多块,由多个线程一起执行,最后合并多个线程的结果,如:求1到100的和,我们分10个线程,分别求1~10,……,90~100的和,然后合并十个线程的结果。还有就是使用线程安全集合,可参加第二天的文章。其实Task的同步机制做已经很好了,如果有特殊业务需求,有线程同步问题,大家可一起交流~~ 二、Task和线程池之间的抉择 我们要说的task的知识也说的差不多了,接下来我们开始站在理论上了解下“线程池”和“任务”之间的关系,我们要做到知其然,还要知其所以然。不管是说线程还是任务,我们都不可避免的要讨论下线程池,然而在.net 4.0以后,线程池引擎考虑了未来的扩展性,已经充分利用多核微处理器架构,只要在可能的情况下,我们应该尽量使用task,而不是线程池。 这里简要的分析下CLR线程池,其实线程池中有一个叫做“全局队列”的概念,每一次我们使用QueueUserWorkItem的使用都会产生一个“工作项”,然后“工作项”进入“全局队列”进行排队,最后线程池中的的工作线程以FIFO(First Input First Output)的形式取出,这里值得一提的是在.net 4.0之后“全局队列”采用了无锁算法,相比以前版本锁定“全局队列”带来的性能瓶颈有了很大的改观。那么任务委托的线程池不光有“全局队列”,而且每一个工作线程都有”局部队列“。我们的第一反应肯定就是“局部队列“有什么好处呢?这里暂且不说,我们先来看一下线程池中的任务分配,如下图: 线程池的工作方式大致如下,线程池的最小线程数是6,线程1~3正在执行任务1~3,当有新的任务时,就会向线程池请求新的线程,线程池会将空闲线程分配出去,当线程不足时,线程池就会创建新的线程来执行任务,直到线程池达到最大线程数(线程池满)。总的来说,只有有任务就会分配一个线程去执行,当FIFO十分频繁时,会造成很大的线程管理开销。 下面我们来看一下task中是怎么做的,当我们new一个task的时候“工作项”就会进去”全局队列”,如果我们的task执行的非常快,那么“全局队列“就会FIFO的非常频繁,那么有什么办法缓解呢?当我们的task在嵌套的场景下,“局部队列”就要产生效果了,比如我们一个task里面有3个task,那么这3个task就会存在于“局部队列”中, 如下图的任务一,里面有三个任务要执行,也就是产生了所谓的"局部队列",当任务三的线程执行完成时,就会从任务一种的队列中以FIFO的形式"窃取"任务执行 ,从而减少了线程管理的开销。这就相当于,有两个人,一个人干完了分配给自己的所有活,而另一个人却还有很多的活,闲的人应该接手点忙的人的活,一起快速完成。 从上面种种情况我们看到,这些分流和负载都是普通ThreadPool.QueueUserWorkItem所不能办到的,所以说在.net 4.0之后,我们尽可能的使用TPL,抛弃ThreadPool。 这是5天玩转C#并行和多线程编程系列的最后一篇了,当然还有很多东西没说到,如果真的想要玩转多线程,还是要多多努力学习的。大家在学习过程中有什么问题可以一起交流~~ 如果大家感觉我的博文对大家有帮助,请推荐支持一把,给我写作的动力。 from:http://www.tuicool.com/articles/2maqYrI

龙生   11 Sep 2016
View Details

c#使用多线程的几种方式示例详解

(1)不需要传递参数,也不需要返回参数 ThreadStart是一个委托,这个委托的定义为void ThreadStart(),没有参数与返回值。 复制代码代码如下: class Program{ static void Main(string[] args) { for (int i = 0; i < 30; i++) { ThreadStart threadStart = new ThreadStart(Calculate); Thread thread = new Thread(threadStart); thread.Start(); } Thread.Sleep(2000); Console.Read(); } public static void Calculate() { DateTime time = DateTime.Now;//得到当前时间 Random ra = new Random();//随机数对象 Thread.Sleep(ra.Next(10,100));//随机休眠一段时间 Console.WriteLine(time.Minute + ":" + time.Millisecond); } } (2)需要传递单个参数 ParameterThreadStart委托定义为void ParameterizedThreadStart(object state),有一个参数但是没有返回值。 复制代码代码如下: class Program{ static void Main(string[] args) { for (int i = 0; i < 30; i++) { ParameterizedThreadStart tStart = new ParameterizedThreadStart(Calculate); Thread thread = […]

龙生   11 Sep 2016
View Details

Asp.net+Mysql,查询出错:由于连接方在一段时间后没有正确答复或连接的主机没有反应,连接尝试失败

在网上看到的解决方案基本都是说host文件中127.0.0.1 localhost 的对应, 但我查看了host文件,并没有问题,纠结半天,拿查询语句在Mysql Workbench上执行,报了一个错,说是子查询包含多个结果,我去~!这很简单的一个错误asp.net竟然没能准确反馈。 于是在子查询语句后面加limit 1,Ok~ 所以,出现“由于连接方在一段时间后没有正确答复或连接的主机没有反应,连接尝试失败”这个错误时,有可能是查询语句有问题,而不是连接有问题。 from:http://blog.csdn.net/idoiknow/article/details/8923553

龙生   07 Sep 2016
View Details

NPOI读写Excel

1、整个Excel表格叫做工作表:WorkBook(工作薄),包含的叫页(工作表):Sheet;行:Row;单元格Cell。 2、NPOI是POI的C#版本,NPOI的行和列的index都是从0开始 3、POI读取Excel有两种格式一个是HSSF,另一个是XSSF。 HSSF和XSSF的区别如下: HSSF is the POI Project’s pure Java implementation of the Excel ’97(-2007) file format. XSSF is the POI Project’s pure Java implementation of the Excel 2007 OOXML (.xlsx) file format. 即:HSSF适用2007以前的版本,XSSF适用2007版本及其以上的。 下面是用NPOI读写Excel的例子:ExcelHelper封装的功能主要是把DataTable中数据写入到Excel中,或者是从Excel读取数据到一个DataTable中。 ExcelHelper类:

测试代码:

Excel相关DLL下载:NPOI-Lib.rar   1.NPOI下载地址:http://npoi.codeplex.com/releases/view/38113 2.NPOI学习系列教程推荐:http://www.cnblogs.com/tonyqus/archive/2009/04/12/1434209.html   参考: http://www.cnblogs.com/Erik_Xu/archive/2012/06/08/2541957.html http://www.cnblogs.com/linzheng/archive/2010/12/20/1912137.html http://www.cnblogs.com/knowledgesea/archive/2012/11/16/2772547.html   from:http://www.cnblogs.com/luxiaoxun/p/3374992.html

龙生   06 Sep 2016
View Details

Entity Framework – 直接执行数据库命令

原文地址: http://msdn.microsoft.com/en-us/library/gg715124(v=vs.103)   使用 EF 4.1 或者更新版本, 你可以直接执行任何数据库命令. 在本节介绍的方法允许你对数据库执行原生的 SQL 命令.   通过 SQL 查询语句获取实体对象集 DbSet 类中的 SqlQuery 方法允许你执行一个返回实体对象集的原生 SQL 查询. 默认情况下, 返回的对象集会被上下文跟踪; 这可以通过对方法返回的 DbSqlQuery 对象调用 AsNoTracking 方法取消.返回的结果集一般为 DbSet 所对应的类型, 否则即便是其派生类也无法返回. 如果所查询的表包含了其他实体类型的数据, 那么所执行的 SQL 语句应该被正确书写, 保证只返回指定类型实体的数据. 下面的例子使用 SqlQuery 方法执行了一个 SQL 查询, 返回一个 Department 类型的实例集.

译注: AsNoTracking 方法必须再查询执行前调用, 查询执行后调用无效. 通过 SQL 查询获取非实体对象集 通过 Database 类中的 SqlQuery 方法来执行原生 SQL 命令, 可以返回任何类型的实例, 包括 .Net 中的原生类型. 但获取的数据将不会被上下文对象跟踪, 即使我们用这个方法来检索实体对象. 如:

让数据库执行原生的非查询 SQL 命令 可以通过 Database 类中的 ExecuteSqlCommand 方法执行非查询命令. 例如:

ExecuteSqlCommand 方法有时会被用在 Code First 创建的数据库的初始化函数中, 用来对数据库进行一些额外的配置 (例如, 设置索引). 需要注意的是, 上下文对象并不知道执行了 ExecuteSqlCommand […]

龙生   03 Sep 2016
View Details
1 115 116 117 175