.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线程占用过多等问题,这个时候我们需要更多的是用异步编程来修正这些问题,但是通常都是说起来容易做起来难,诚然异步编程相对于同步编程来说,它是一 ...
随机推荐
- U8API——向U8数据库表导入数据
一.打开API资源管理器 替换两个引用 打开应用实例,选择相应的功能 复制相应的封装类到自己的目录下 在数据库新建临时表,与目标表相同 数据导入: 思路:先将要导入的数据导入到与U8目标表相同的临时表 ...
- java --Method
MethodDemo class MethodDemo { public static void main(String[] args) { //调用自定义的方法. draw(4,5); draw(8 ...
- Hive导出表数据
法一: hive (stuchoosecourse) > insert overwrite local directory '/home/landen/文档/exportDir' ...
- centos 6.8 解决ibus输入法不正常显示的问题
今天发现 ibus输入法打字时不正常显示,如下图
- 模拟登陆+数据爬取 (python+selenuim)
以下代码是用来爬取LinkedIn网站一些学者的经历的,仅供参考,注意:不要一次性大量爬取会被封号,不要问我为什么知道 #-*- coding:utf-8 -*- from selenium impo ...
- HTML编码规范 - 1
用两个空格来代替制表符(tab) -- 这是唯一能保证在所有环境下获得一致展现的方法. 嵌套元素应当缩进一次(即两个空格). 对于属性的定义,确保全部使用双引号,绝不要使用单引号. 不要在自闭和(se ...
- 使用Intent在活动之间穿梭
使用Intent在活动之间穿梭 1.在com.example.activitytest中创建第二个活动SecondActivity: /** * 第二个活动 */ public class Secon ...
- thymeleaf的常见问题汇总
thymeleaf的常见问题汇总 1.thymeleaf th:href 多个参数传递格式 th:href="@{/Controller/update(param1=1,param2=${p ...
- python 把一文件包含中文的字符写到另外文件乱码 UnicodeDecodeError: 'gbk' codec can't decode byte 0xac in position
报错的代码是: file2 = open('target.txt','w')for line in open('test.txt'): file2.write(line)原因:文件编码不一致导致解决方 ...
- VS2015 未能正确加载 JavascriptWebExtensionsPackage
解决方法: Close Visual Studio Open the %UserProfile%\AppData\Local\Microsoft\VisualStudio\<version> ...
