浅谈.NET下的多线程和并行计算(十).NET异步编程模型基础 上

谈多线程谈到现在,我们要明确多线程的一个好处是可以进行并行的运算(充分利用多核处理器,对 于桌面应用程序来说就更重要一点了,没有WEB服务器,利用多核只能靠自己),还有一个好处就是异步 操作,就是我们可以让某个长时间的操作独立运行,不妨碍主线程继续进行一些计算,然后异步的去返回 结果(也可以不返回)。前者能提高性能是因为能利用到多核,而后者能提高性能是因为能让CPU不在等 待中白白浪费,其实异步从广义上来说也可以理解为某种并行的运算。在之前的这么多例子中,我们大多 采用手工方式来新开线程,之前也说过了,在大并发的环境中随便开始和结束线程的代价太大,需要利用 线程池,使用线程池的话又觉得少了一些控制。现在让我们来总结一下大概会有哪几种常见的异步编程应 用模式:

1) 新开一个A线程执行一个任务,然后主线程执行另一个任务后等待线程返回结果后继续

2) 新开一个A线程执行一个任务,然后主线程不断轮询A线程是否执行完毕,如果没有的话可以选择 等待或是再进行一些操作

3) 新开一个A线程执行一个任务,执行完毕之后立即执行一个回调方法去更新一些状态变量,主线程 和A线程不一定有直接交互

4) 新开一个A线程执行一个任务,执行完毕之后啥都不做

(补充一句,异步编程不一定是依赖于线程的,从广义上来说,使用队列异步处理数据也可以算是一 种异步编程模式)

对于这任何一种,我们要使用线程池来编写应用的话都是比较麻烦的,比如如下的代码实现了1)这种 应用:

class AsyncObj
{
   public EventWaitHandle AsyncWaitHandle { get; set; }
   public object Result { get; set; }

   public AsyncObj()
   {
     AsyncWaitHandle = new AutoResetEvent(false);
   }
}

AsyncObj ao = new AsyncObj();
ThreadPool.QueueUserWorkItem(state =>
{
   AsyncObj obj = state as AsyncObj;
   Console.WriteLine("asyc operation started @ " + DateTime.Now.ToString ("mm:ss"));
   Thread.Sleep(2000);
   Console.WriteLine("asyc operation completed @ " + DateTime.Now.ToString ("mm:ss"));
   obj.Result = 100;
   obj.AsyncWaitHandle.Set();
}, ao);

Console.WriteLine("main operation started @ " + DateTime.Now.ToString("mm:ss"));
Thread.Sleep(1000);
Console.WriteLine("main operation completed @ " + DateTime.Now.ToString ("mm:ss"));
ao.AsyncWaitHandle.WaitOne();
Console.WriteLine("get syc operation result : " + ao.Result.ToString() + " @ "  + DateTime.Now.ToString("mm:ss"));

结果如下:

时间: 2025-01-20 19:00:04

浅谈.NET下的多线程和并行计算(十).NET异步编程模型基础 上的相关文章

浅谈.NET下的多线程和并行计算(三)线程同步基础 上

其实,如果线程都是很独立的,不涉及到任何资源访问的,那么这些毫无干扰的线程不会产生什么问 题.但是在实际应用中我们的线程总是涉及到资源访问的,而且往往涉及到共享资源的访问,那么就产生 了线程同步的问题.一直觉得线程同步这个名词很奇怪,字面上看同步就是使得步调一致,线程同步是不 是就是让线程步调一致的访问资源呢?事实上反了,线程同步恰巧是让线程不同时去访问资源而是去按照 我们期望的顺序依次访问资源(是同步资源访问的行为而不是同步同时访问资源).一句话,多个线程( 不仅仅局限于相同进程)如果需要访问

浅谈.NET下的多线程和并行计算(五)线程池基础 上

池(Pool)是一个很常见的提高性能的方式.比如线程池连接池等,之所以有这些池是因为线程和数 据库连接的创建和关闭是一种比较昂贵的行为.对于这种昂贵的资源我们往往会考虑在一个池容器中放置 一些资源,在用的时候去拿,在不够的时候添点,在用完就归还,这样就可以避免不断的创建资源和销毁 资源. 如果您做过相关实验的话可能会觉得不以为然,似乎开1000个线程也用不了几百毫秒.我们要这么想 ,对于一个高并发的环境来说,每一秒假设有100个请求,每个请求需要使用(开和关)10个线程,也就 是一秒需要处理10

浅谈.NET下的多线程和并行计算(四)线程同步基础 下

回顾一下上次,我们讨论了lock/AutoResetEvent/ManualResetEvent以及Semaphore.这些用于线程同 步的结构叫做同步基元.同步基元从类型上可以分为锁定/通知/联锁三种.lock显然锁定方式,而且是独 占锁定,也就是在锁释放之前不能由其它线程获得. Semaphore也是一种锁定,只不过不是独占锁,可以 指定多少个线程访问代码块.AutoResetEvent和ManualResetEvent当然就是通知方式了,前者在通行之后 自动重置,后者需要手动重置.我们还看

浅谈.NET下的多线程和并行计算(六)线程池基础 下

这节我们按照线程池的核心思想来自定义一个简单的线程池: 1) 池中使用的线程不少于一定数量,不多于一定数量 2) 池中线程不够的时候创建,富裕的时候收回 3) 任务排队,没有可用线程时,任务等待 我们的目的只是实现这些"需求",不去考虑性能(比如等待一段时间再去创建新的线程等策略)以 及特殊的处理(异常),在实现这个需求的过程中我们也回顾了线程以及线程同步的基本概念. 首先,把任务委托和任务需要的状态数据封装一个对象: public class WorkItem { public Wa

浅谈.NET下的多线程和并行计算(十一).NET异步编程模型基础 下

上次我们说了,要进行多线程编程,我们可以使用最原始的方式也是最灵活的方式进行,那就是 Thread(ThreadPool)+信号量+ 锁+Control.Invoke..NET的异步编程模型给我们提供了一种基于 IAsyncResult的编程模式,它尤其适用于处理下面的应用场景: 1) 被阻止,正在等待一个 IAsyncResult 2) 被阻止,正在等待多个 IAsyncResult 对象 3) 轮询 IAsyncResult 上的完成情形 .NET还提供了基于事件的异步编程模式,它能够提供:

浅谈.NET下的多线程和并行计算(十四)并行计算前言

之前的文章中我们介绍了如何在.NET下运用相关类库进行多线程编程的基础,我们知道.NET 4.0已经 正式推出了,带来的重要特性是并行库.本文就谈谈对并行计算的一些理解和看法.并行计算不是一个很 新的概念,其实它就是通过多线程把同一个任务分割成多个子任务并行的执行的过程..NET 4.0并行库不 但提供了这方面的支持,而且还封装了多线程开发的各种场景,使得我们不需要依赖Thread/同步基元等 "底层"的对象就可以进行多线程开发.没有.NET 4.0的并行计算库我们同样可以进行并行计算

浅谈.NET下的多线程和并行计算(一)前言

作为一个ASP.NET开发人员,在之前的开发经历中接触多线程编程的机会并不是很多,但是随着.NET 4.0的发布临近,我越来越感受到未来的1-2年中并行计算将会有很大的应用.于是决定通过写日志的方式 来总结一下.NET 3.5下的多线程编程进而引入.NET 4.0提供的新的并行库以及新的并行编程模式和编程的 思维方式. 个人觉得在日常的编程中对于ASP.NET程序员来说使用多线程编程不是很多,其实我们无时无刻不在享 受多线程的优势.首先,WEB服务器环境就是一个多线程环境,每一个请求都是独立的线

浅谈.NET下的多线程和并行计算(九)Winform中多线程编程基础 下

在之前的文章中我们介绍过两种Timer和BackgroundWorker组件,在上文中我们提到过,强烈建议在UI 线程上操作控件,否则很容易产生人品问题.可以想到,上次介绍的两个Timer基于ThreadPool,回调方 法运行于不同于UI线程的新线程上,在这个方法中操作控件需要进行 Invoke或BeginInvoke.其实,还有 第三种System.Windows.Forms.Timer,它可以让回调事件在UI线程上执行,我们来做一个实验比较一下 System.Windows.Forms.T

浅谈.NET下的多线程和并行计算(八)Winform中多线程编程基础 上

首先我们创建一个Winform的应用程序,在上面添加一个多行文本框和一个按钮控件,按钮的事件如下 : Thread.Sleep(1000); StringBuilder sb = new StringBuilder(); for (int i = 0; i < 10000; i++) sb.Append("test"); string s = sb.ToString(); textBox1.Text = s; 首先我们可以把这个操作理解为一个非常耗时的操作,它至少占用1秒的时间.