.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线程占用过多等问题,这个时候我们需要更多的是用异步编程来修正这些问题,但是通常都是说起来容易做起来难,诚然异步编程相对于同步编程来说,它是一 ...
随机推荐
- 萝卜保卫战3内购破解+Toast窗口增加(Love版)
涉及到一些不同的破解的方法,以及不同的破解思路,还有一些重要权限的删除等. 作者:HAI_ 这次目标是经常玩的萝卜保卫战,不知不觉,已经更新到3了.详细分析请参考https://bbs.ichunqi ...
- Ubuntu软件更新时出错问题解决
apt-get instal update 提示:错误,无法解析域名等等之类的 网上解决办法一大堆,先别急着用网上的方法,来检查检查系统是否有网络连接 网络图标显示网络连接,等等,别被表面迷惑了,命令 ...
- SQL实现数据行列转换
前言: 在日常的工作中,使用数据库查看数据是很经常的事,数据库的数据非常多,如果此时的数据设计是一行行的设计话,就会有多行同一个用户的数据,查看起来比较费劲,如果数据较多时,不方便查看,为了更加方便工 ...
- 【Java】认识 JDK,JRE,JVM
JDK,JRE,JVM 今天我们讨论下这三个Java工具 JDK 全称Java Development ToolKit(Java 开发工具包). JDK是整个JAVA的核心,其包括了Java运行环境( ...
- mysql ERROR 1045 (28000): Access denied for user 可能解决方法分析
在实际登录redmine的过程中,我们遇到了如下的error ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using ...
- oracle_jdbc_Query
本例子程序是根据马士兵老师所讲+自己的注释.写的比较全面,特别是最后释放资源的代码. package com.ayang.jdbc; import java.sql.*; public class T ...
- Failed to instantiate [java.util.List]: Specified class is an interface
错误信息提示: Failed to instantiate [java.util.List]: Specified class is an interface; 错误信息意思:参数错误,参数封装出了问 ...
- 【Java并发编程】:并发新特性—障碍器CyclicBarrier
CyclicBarrier(又叫障碍器)同样是Java5中加入的新特性,使用时需要导入Java.util.concurrent.CylicBarrier.它适用于这样一种情况:你希望创建一组任务,它们 ...
- Android 开发工具类 23_getImage
pathText = "http://192.168.1.100:8080/ServerForPicture/wangjialin.jpg" import java.io.Inpu ...
- Android PdfViewer
今天按项目要求找了一个android的PDF控件,各种操作效果都非常好,在这里和大家分享一下. 这是github的地址:https://github.com/barteksc/AndroidPdfVi ...
