.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线程占用过多等问题,这个时候我们需要更多的是用异步编程来修正这些问题,但是通常都是说起来容易做起来难,诚然异步编程相对于同步编程来说,它是一 ...
随机推荐
- mybatis 关联表查询
这段时间由于项目上的需求:需要将数据库中两表关联的数据查询出来展示到前端(包含一对一,一对多): (1)一对一: 在实体类中维护了另一个类的对象: 这里我以用户(User)和产品(Product)为例 ...
- ubuntu14.0 安装 node v8.11.1(任意版本)
由于众所周知的原因,通过node官网下载速度十分慢,我这里通过淘宝镜像安装 node8.11.1,其他版本同理. node版本淘宝镜像地址:https://npm.taobao.org/mirrors ...
- 使用request.js代理post失败的问题
前面写过一篇使用request.js做代理的文章,可能眼睛敏锐的朋友已经看出在代理POST方法时和代理其它请求方式是有区别的, 现在我来说一下为什么要这么处理. 相信很多人都采用这种方式去代理POST ...
- 原来css也可以计算-calc()使用
在浏览其他人的源代码时,看到了一个陌生的属性:width:calc(100% - 10px -10px); 出于好奇心,百度了一下,看到了以下这篇文章,http://www.w3cplus.com/c ...
- java中的IO流(输入流与输出流)概述与总结
Java中IO流,输入输出流概述与总结 总结的很粗糙,以后时间富裕了好好修改一下. 1:Java语言定义了许多类专门负责各种方式的输入或者输出,这些类都被放在java.io包中.其中, 所有输入流类都 ...
- NSCache 的好处
相较于 NSDictionary 线程安全 系统资源将要耗尽时,自动删减缓存 自动删减"最久未使用的"对象 不会自动拷贝键.因为有些键不支持拷贝操作 可以和 NSPurgeable ...
- n层满k叉树总共有多少个节点
2叉树 1 3 7 对应公式为(2^n-1)/1 3叉树 1 4 13 对应公式为(3^n-1)/2 4叉树 1 5 21对应公式为(4^n-1)/3 ... n层k叉树,总共有(k^n-1)/k-1 ...
- docker私服registry管理镜像
前言 首先试想这样一个场景:当在自己的机器上(docker中)构建了mysql镜像,eureka镜像等等微服务镜像,这些镜像有可能需要放到其他的机器上docker环境中去运行,实行分布式架构部署.但如 ...
- Linux 基础命令 持续更新中...
1.ls 显示当前文件/文件夹 显示文件大小: ls -lh 显示隐藏文件: ls -a 显示文件详细信息: ls -l (ll)2.pwd 显示当前所在路径 cat 显示当前文件下所有内容3.cd ...
- 【BZOJ3456】轩辕朗的城市规划 EGF+多项式求ln
我们构造$f(i)$和$g(i)$. 其中$f(x)$表示由$x$个节点构成的无向简单连通图的个数. $g(x)$表示有$x$个节点构成的无向简单图(不要求连通)的个数. 显然,由$x$个节点构成的无 ...
