首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

小弟我所知道的.NET异步

2012-09-10 
我所知道的.NET异步对于异步,相信大家都不十分陌生。准确点来说就是方法执行后立即返回,待到执行完毕会进行

我所知道的.NET异步

对于异步,相信大家都不十分陌生。准确点来说就是方法执行后立即返回,待到执行完毕会进行通知。就是当一个任务在执行的时候,尤其是需要耗费很长的时间进行处理的任务,如果利用单线程进行操作的话,势必造成界面的阻塞;而利用异步方式,则不会出现这种情况。 区别于同步处理,可以说阻塞的异步其实就相当于同步。

其实上面的图片是我运行了一段时间的程序的截图,但是由于作用在了同步模式下,导致界面阻塞,从而产生极差的用户体验。

代码如下:

小弟我所知道的.NET异步

代码如下:

这里是撤销后的操作:

小弟我所知道的.NET异步

那么是如何实现的呢?我们先从BackgroundWorker注册的几个事件说起:

首先是DoWork事件,他的注册方式如下:

小弟我所知道的.NET异步View Code
#region 第一步:加载数据到内存        private void ReadIntoMemory(BackgroundWorker worker, DoWorkEventArgs e)        {            if (String.IsNullOrEmpty(fileName))            {                MessageBox.Show("文件名不能为空!");                return;            }            string result;            long mainCount = 0;            using (StreamReader sr = new StreamReader(fileName, Encoding.Default))            {                while ((result = sr.ReadLine()) != null)                {                    mainCount++;                    recordList.Add(result); //添加记录到List中存储,以便在下一步进行处理。                    double statusResult = (double)mainCount / (double)totalCount;                    syncContext.Send(new SendOrPostCallback((s) =>                    {                        if (worker.CancellationPending) //检测到用户取消任务                        {                            e.Cancel = true;  //任务取消                        }                        else                        {                            lblCurrentRecords.Text = mainCount.ToString();                            lblStatus.Text = statusResult.ToString("p");                            int thisPercentange = Int32.Parse((Math.Floor(statusResult * 100)).ToString());                            //pbMain.Value = thisPercentange;                            worker.ReportProgress(thisPercentange); //报告当前的进度                            tsNotify.Text = "| 当前导入";                        }                    }), null);                }            }        }        #endregion

再说说利用task的实现的方式

?关于Task类,可以说在4.0之前从来没有见过,使用起来非常的简单,也很方便。其实,对于Task类,我也是参考了诸多文章,下面的这句话,引用自另外一篇文章:

Task在并行计算中的作用很凸显,首次构造一个Task对象时,他的状态是Created。以后,当任务启动时,他的状态变成WaitingToRun。Task在一个线程上运行时,他的状态变成Running。任务停止运行,并等待他的任何子任务时,状态变成WaitingForChildrenToComplete。任务完全结束时,它进入以下三个状态之一:RanToCompletion,Canceled或者Faulted。一个Task<TResult>运行完成时,可通过Task<TResult>的Result属性来查询任务的结果,一个Task或者Task<TResult>出错时,可以查询Task的Exception属性来获得任务抛出的未处理的异常,该属性总是返回一个AggregateException对象,他包含所有未处理的异常。
为简化代码,Task提供了几个只读的Boolean属性,IsCanceled,IsFaulted,IsCompleted。注意,当Task处于RanToCompleted,Canceled或者Faulted状态时,IsCompleted返回True。为了判断一个Task是否成功完成,最简单的方法是if(task.Status == TaskStatus.RanToCompletion)。

当然,我们还是以上面的例子来进行编程与讲解。

首先,我们要开启一个Task,那么Task taskOne = new Task(ReadIntoMemory);表示将ReadIntoMemory函数注册成为了任务来运行,然后利用taskOne.Start();来开启任务。那么如何运行第二个任务,并且还要等到第一个运行完成之后呢? 这里我们就需要用到其ContinueWith方法:

Task taskTwo = taskOne.ContinueWith(Action => { ProcessRecords(); });

这样,就行了那么当运行的时候,程序的确会按照顺序来启动任务。图示和APM模式中的图片相同,我就不贴了,下面是代码:

            Task taskOne = new Task(ReadIntoMemory);            taskOne.Start();            Task taskTwo = taskOne.ContinueWith(Action => { ProcessRecords(); });
复制代码

Task<TResult>泛型方法中的TResult为返回值类型,承载的是一个无参,但是有返回值的任务。所以传入的函数要么是有一个参数带返回值的;要么就是无参数带返回值的,要么就是无参数无返回值的。如果是一个参数,有返回值的话,可以利用下面的方式来进行:

Task<int> taskOne = new Task<int>(a=>ReadIntoMemory((int)a),5);

热点排行