.NET中的异步编程
开篇
异步编程是程序设计的重点也是难点,还记得在刚开始接触.net的时候,看的是一本c#的Winform实例教程,上面大部分都是教我们如何使用Winform的控件以及操作数据库的实例,那时候做的基本都是数据库的demo,数据量也不大,程序在执行的时候基本上不会出现阻塞的情况。随着不断的深入.net,也开始进入的实战,在实际的项目,数据量往往都是比较大,特别是在大量的数据入库以及查询数据并进行计算的时候,程序的UI界面往往卡死在那里,发生了阻塞,这时候就需要对计算时间限制的过程进行异步处理,让UI线程继续相应用户的操作,使得用户体验表现比较友好,同时正确的使用异步编程去处理计算限制的操作和耗时IO操作还能提升的应用程序的吞吐量及性能。由此可见,异步编程的重要性。
class Program
{
public delegate void DoWork();
static void Main(string[] args)
{
DoWork d = new DoWork(WorkPro);//no.1 d.BeginInvoke(null, null);//no.2
for (int i = ; i < ; i++)//no.3
{
Thread.Sleep();//主线程需要做的事
}
Console.WriteLine("主线程done");
Console.ReadKey();
}
public static void WorkPro()
{
//做一些耗时的工作
Thread.Sleep();
Console.WriteLine("异步调用结束");
}
}

class Program
{
public delegate int DoWord(int count);
static void Main(string[] args)
{
DoWord d = new DoWord(WorkPro);
IAsyncResult r= d.BeginInvoke(,null,null);//no.1
int result= d.EndInvoke(r);//no.2
Console.WriteLine(result);
for (int i = ; i < ; i++)//no.3
{
Thread.Sleep();//主线程需要做的事
}
Console.WriteLine("主线程done");
Console.ReadKey();
}
public static int WorkPro(int count)
{
int sum = ;
//做一些耗时的工作
for (int i = ; i < count; i++)
{
sum += i;
}
return sum;
}
}
class Program
{
public delegate int DoWord(int count);
static void Main(string[] args)
{
DoWord d = new DoWord(WorkPro);
IAsyncResult r= d.BeginInvoke(,CallBack ,d);//no.1
for (int i = ; i < ; i++)
{
Thread.Sleep();//主线程需要做的事
}
Console.WriteLine("主线程done");
Console.ReadKey();
}
public static int WorkPro(int count)
{
int sum = ;
//做一些耗时的工作
for (int i = ; i < count; i++)
{
sum += i;
Thread.Sleep();
}
return sum;
} public static void CallBack(IAsyncResult r)
{
DoWord d = (DoWord)r.AsyncState;
Console.WriteLine("异步调用完成,返回结果为{0}", d.EndInvoke(r));
}
}
.net在System.Threading和System.Threading.Tasks这两个命名空间中提供了Thread,ThreadPool,和Task三个类来处理多线程的问题,其中Thread是建立一个专用线程,ThreadPool是使用线程池中工作线程,而Task类是采用任务的方式,其内部也是使用线程池中的工作线程。本节只讲Tread类和Tasks类的使用以及其优劣。
class Program
{
static void Main(string[] args)
{
Thread t = new Thread(WorkPro);//no.1
t.IsBackground = true;//no.2
t.Start();//no.3
}
public static void WorkPro(object t)
{
//做一些耗时的工作
int count=(int)t;
for (int i = ; i < count; i++)
{
Thread.Sleep();
} Console.WriteLine("任务处理完成");
}
}
2、Task类
class Program
{
static void Main(string[] args)
{
Task t = new Task((c) =>
{
int count = (int)c;
for (int i = ; i < count; i++)
{
Thread.Sleep();
}
Console.WriteLine("任务处理完成");
}, );//no.1
t.Start(); for (int i = ; i < ; i++)
{
Thread.Sleep();
}
Console.WriteLine("done");
}
}
class Program
{
static void Main(string[] args)
{
Task<int> t = new Task<int>((c) =>
{
int count = (int)c;
int sum=;
for (int i = ; i < count; i++)
{
Thread.Sleep();
sum+=i;
}
Console.WriteLine("任务处理完成");
return sum;
}, );
t.Start();
t.Wait();//no.1
Console.WriteLine("任务执行的结果{0}", t.Result);//no.2
for (int i = ; i < ; i++)
{
Thread.Sleep();
}
Console.WriteLine("done");
}
}
class Program
{
static void Main(string[] args)
{
CancellationTokenSource cts = new CancellationTokenSource();//no.1
Task<int> t = new Task<int>((c) =>Sum(cts.Token ,(int)c), );//no.2
t.Start();
cts.Cancel();//no.3如果任务还没完成,但是Task有可能完成啦
for (int i = ; i < ; i++)
{
Thread.Sleep();
}
Console.WriteLine("done");
}
static int Sum(CancellationToken ct, int count)
{
int sum = ;
for (int i = ; i < count; i++)
{
if (!ct.CanBeCanceled)
{
Thread.Sleep();
sum += i;
}
else
{
Console.WriteLine("任务取消");
//进行回滚操作
return -;//退出任务
}
}
Console.WriteLine("任务处理完成");
return sum;
}
}
public Task ContinueWith( Action<Task> continuationAction, TaskContinuationOptions continuationOptions )第二个参数代表新任务的执行条件,当任务满足这个枚举条件才执行 Action<Task>类型的回调函数。
class Program
{
static void Main(string[] args)
{
Task<int> t = new Task<int>((c) =>Sum((int)c), );
t.Start();
t.ContinueWith(task => Console.WriteLine("任务完成的结果{0}", task.Result));//当任务执行完之后执行
t.ContinueWith(task => Console.WriteLine(""), TaskContinuationOptions.OnlyOnFaulted);//当任务出现异常时才执行
for (int i = ; i < ; i++)
{
Thread.Sleep();
}
Console.WriteLine("done");
}
static int Sum( int count)
{
int sum = ;
for (int i = ; i < count; i++)
{
Thread.Sleep();
sum += i;
}
Console.WriteLine("任务处理完成");
return sum;
}
}
t.Start()之后调用第一个ContinueWith方法,该方法第一参数就是一个Action<Task>的委托类型,相当于是一个回调函数,在这里我也用lambda表达式,当任务完成就会启用一个新任务去执行这个回调函数。而第二个ContinueWith里面的回调方法却不会执行,因为我们的任务也就是Sum方法不会发生异常,不能满足TaskContinuationOptions.OnlyOnFaulted这个枚举条件。这种用法比委托的异步函数编程看起来要简单些。最关键的是ContinueWith的还有一个重载版本可以带一个TaskScheduler对象参数,该对象负责执行被调度的任务。FCL中提供两种任务调度器,均派生自TaskScheduler类型:线程池调度器,和同步上下文任务调用器。而在Winform窗体程序设计中TaskScheduler尤为有用,为什么这么说呢?因为在窗体程序中的控件都是有ui线程去创建,而我们所执行的后台任务使用线程都是线程池中的工作线程,所以当我们的任务完成之后需要反馈到Winform控件上,但是控件创建的线程和任务执行的线程不是同一个线程,如果在任务线程中去更新控件就会导致控件对象安全问题会出现异常。所以操作控件,就必须要使用ui线程去操作。因此在ContinueWith获取任务执行的结果的并反馈到控件的任务调度上不能使用线程池任务调用器,而要使用同步上下文任务调度器去调度,即采用ui这个线程去调用ContinueWith方法所绑定的回调用函数即Action<Task>类型的委托。下面将使用任务调度器来把异步执行的Sum计算结果反馈到Winform界面的TextBox控件中。
界面如下。
.com/79f73939083f499f8bd54fc2dd972d06/clipboard.png)
代码如下。
public partial class Form1 : Form
{
private readonly TaskScheduler contextTaskScheduler;//声明一个任务调度器
public Form1()
{
InitializeComponent();
contextTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();//no.1获得一个上下文任务调度器
} private void button1_Click(object sender, EventArgs e)
{
Task<int> t = new Task<int>((n) => Sum((int)n),);
t.Start();
t.ContinueWith(task =>this.textBox1 .Text =task.Result.ToString(),contextTaskScheduler);//当任务执行完之后执行
t.ContinueWith(task=>MessageBox .Show ("任务出现异常"),CancellationToken.None ,TaskContinuationOptions.OnlyOnFaulted,contextTaskScheduler );//当任务出现异常时才执行
}
int Sum(int count)
{
int sum = ;
for (int i = ; i < count; i++)
{
Thread.Sleep();
sum += i;
}
Console.WriteLine("任务处理完成");
return sum;
}
}
.NET中的异步编程的更多相关文章
- .Net中的异步编程总结
一直以来很想梳理下我在开发过程中使用异步编程的心得和体会,但是由于我是APM异步编程模式的死忠,当TAP模式和TPL模式出现的时候我并未真正的去接纳这两种模式,所以导致我一直没有花太多心思去整理这两部 ...
- C#中的异步编程Async 和 Await
谈到C#中的异步编程,离不开Async和Await关键字 谈到异步编程,首先我们就要明白到底什么是异步编程. 平时我们的编程一般都是同步编程,所谓同步编程的意思,和我们平时说的同时做几件事情完全不同. ...
- .NET中的异步编程——常见的错误和最佳实践
在这篇文章中,我们将通过使用异步编程的一些最常见的错误来给你们一些参考. 背景 在之前的文章<.NET中的异步编程——动机和单元测试>中,我们开始分析.NET世界中的异步编程.在那篇文章中 ...
- javaScript中的异步编程模式
1.事件模型 let button = document.getElementById("my-btn"); button.onclick = function(event) { ...
- Netty 中的异步编程 Future 和 Promise
Netty 中大量 I/O 操作都是异步执行,本篇博文来聊聊 Netty 中的异步编程. Java Future 提供的异步模型 JDK 5 引入了 Future 模式.Future 接口是 Java ...
- 一文说通C#中的异步编程
天天写,不一定就明白. 又及,前两天看了一个关于同步方法中调用异步方法的文章,里面有些概念不太正确,所以整理了这个文章. 一.同步和异步. 先说同步. 同步概念大家都很熟悉.在异步概念出来之前,我 ...
- 一文说通C#中的异步编程补遗
前文写了关于C#中的异步编程.后台有无数人在讨论,很多人把异步和多线程混了. 文章在这儿:一文说通C#中的异步编程 所以,本文从体系的角度,再写一下这个异步编程. 一.C#中的异步编程演变 1. ...
- promise 的基本概念 和如何解决js中的异步编程问题 对 promis 的 then all ctch 的分析 和 await async 的理解
* promise承诺 * 解决js中异步编程的问题 * * 异步-同步 * 阻塞-无阻塞 * * 同步和异步的区别? 异步;同步 指的是被请求者 解析:被请求者(该事情的处理者)在处理完事情的时候的 ...
- 全面解析C#中的异步编程
当我们处理一些长线的调用时,经常会导致界面停止响应或者IIS线程占用过多等问题,这个时候我们需要更多的是用异步编程来修正这些问题,但是通常都是说起来容易做起来难,诚然异步编程相对于同步编程来说,它是一 ...
随机推荐
- hdoj1175 连连看(dfs+剪枝)
处理连连看问题. 要求拐弯方向不多于两次.剪枝很重要!!! 用dir记录当前方向.Orz,居然没想到. #include<iostream> #include<cstring> ...
- Manjaro Linux执行某些命令缺少libtinfo.so.5问题
Manjaro默认有libtinfo.so.6而没有libtinfo.so.5,软件如果需要可执行以下命令安装: sudo pacman -S ncurses5-compat-libs #或 sudo ...
- css style 标签可编辑
一次偶然在鑫大技术博客上发现 style 标签配合contenteditable 可编辑属性 实现动态编辑css 这里我就回顾了下 contenteditable 可编辑属性 (这个属性并无浏 ...
- 【poj3252】 Round Numbers (数位DP+记忆化DFS)
题目大意:给你一个区间$[l,r]$,求在该区间内有多少整数在二进制下$0$的数量$≥1$的数量.数据范围$1≤l,r≤2*10^{9}$. 第一次用记忆化dfs写数位dp,感觉神清气爽~(原谅我这个 ...
- LFR benchmark graphs 人工网络生成程序
人工网络生成程序,可在CSDN上免费下载 或者科学网这边也可以下载 参数 • n: number of vertices;• k: average degree;• maxk: maximum deg ...
- QuantLib 金融计算——高级话题之模拟跳扩散过程
目录 QuantLib 金融计算--高级话题之模拟跳扩散过程 跳扩散过程 模拟算法 面临的问题 "脏"的方法 "干净"的方法 实现 示例 参考文献 如果未做特别 ...
- Spring Security构建Rest服务-1204-Spring Security OAuth开发APP认证框架之Token处理
token处理之一基本参数配置 处理token时间.存储策略,客户端配置等 以前的都是spring security oauth默认的token生成策略,token默认在org.springframe ...
- 【Java并发编程】:守护线程与线程阻塞的四种情况
守护线程 JAVA中有两类线程:User Thread(用户线程).Daemon Thread(守护线程) 用户线程即运行在前台的线程,而守护线程是运行在后台的线程. 守护线程作用是为其他前台线程的运 ...
- php 按照二位数组中某个指定的字段进行排序
/** * 按照二维数组中某个指定的某个字段进行排序 * @param $array 需要被排序的数组 * @param $flag 排序的标志 1,SORT_DESC 降序 2,SORT_ASC 升 ...
- 数据库-转换sql语句
文章描述:主要说明转换成SQL语句的过程.----必要信息(数据库名,表名,条件)转换成SQL语句 一些界面上数据增删改查的操作往往只需要输入一数据库名,表名,加条件就可以进行数据查询了,在这背后是怎 ...
