一文说通C#中的异步编程补遗
前文写了关于C#中的异步编程。后台有无数人在讨论,很多人把异步和多线程混了。
文章在这儿:一文说通C#中的异步编程
所以,本文从体系的角度,再写一下这个异步编程。
一、C#中的异步编程演变
1. 异步编程模型
这是C#中早期的异步模型,通过IAsyncResult接口来实现。
实现的代码大体是这个样子:
class MyClass
{
IAsyncResult BeginAction(para ..., AsyncCallback callback, object state);
T EndAction(IAsyncResult async_result);
}
这种方式在一些库里还有保留,像FileSteam类里的BeginRead和EndRead方法组,就是这种方式。
编程时,不建议用这种方式。
2. 基于事件的异步模型
这是C#中间一个过渡时期的异步模型,核心是基于一个或多个事件、事件处理委托的派生类型,是一种使用多线程的模式。
这个模式在类库里,多用在Winform/WPF中的组件的事件处理,你可以随便拿一个Framework 4.5以前的组件去研究,大多数都是这种方式。
这种方式的实现大体是这个样子:
class MyClass
{
void ActionAsync(para ...);
event ActionCompletedEventHandler action_completed;
}
这种方式使用多线程,所以,它具有多线程的全部特点和要求。
从微软的建议来看,Framework 4.5以后,并不推荐使用这种模式。
3. 基于任务的异步模型
这种异步模型从Framework 4.0以后引入,使用单一方法来表示异步的开始和完成。这是目前推荐的异步开发方式。在上个文章中的异步模式,就是这个方式。
这个方式的代码实现是这样的:
class MyClass
{
Task<T> ActionAsync(para ...);
}
我们所说的异步,包括前文讲的异步,全部是基于这个基于任务的异步模型来讨论。
在这个模型下,前文说过,异步不是多线程。今天再强调一遍,异步不仅不是多线程,同时异步也不一定会使用多线程。
为了防止不提供原网址的转载,特在这里加上原文链接:https://www.cnblogs.com/tiger-wang/p/13428372.html
二、异步模型中的“任务”
先来看看任务:Task和Task<T>,这是异步模型的核心。
这个“任务”,是一种“承诺”,承诺会在稍后完成任务。
它有两个关键字:async和await。注意:是await,不是wait。这儿再强调一下,Task.Wait是个同步方法,用在多线程中等待。Task是Thread的子集,因此继承了Wait方法,但这个方法不是给异步用的。
在某些情况下,异步可以采用多线程来实现,这时候,Task.Wait可以用,但这是以多线程的身份来使用的,用出问题要查线程,而不是异步。
关于异步中Task和async、await配合的部分,可以去看前一个文章。地址在:一文说通C#中的异步编程,这儿不再说了。
三、异步编程的两种模式
1. 单线程模式
先看代码:
Task<string> GetHtmlAsync()
{
var client = new HttpClient();
var gettask = client.GetStringAsync("https://home.cnblogs.com/u/tiger-wang");
return await gettask;
}
这种模式下,这个异步工作于单线程状态。代码虽然返回一个任务Task<T>,在这个任务依然在主线程中,并没有生成一个新的线程。换句话说,这种方式不额外占用线程池资源,也不需要考虑多线程开发中线程锁定、数据一致性等问题。
因为线程没有切换,所以也不存在上下文切换的问题。
2. 多线程模式
既然Task派生自Thread,当然也可以用多线程来实现异步。
看代码:
Task<string> GetHtmlAsync()
{
var gettask = Task.Run(() => {
var client = new HttpClient();
return client.GetStringAsync("https://home.cnblogs.com/u/tiger-wang");
});
return await gettask;
}
对方上一段代码,把调用client.GetStringAsync的部分放到了Task.Run里。
这种方式中,异步被放到了主线程以外的新线程中执行,换句话说,这个异步在以多线程的方式执行。
在这种模式下,async和await的配合,以及对程序执行次序的控制,跟单线程模式是完全一样的。但是要注意,前边说了,async和await是异步的关键字,它不管多线程的事,也不会为多线程提供任何保护。多线程中的并发锁、数据锁、上下文切换,还需要以多线程的方式另外搞定。Task.Run的内部代码会占用线程池资源,并在一个可用的线程上与主线程并行运行。
四、异步的两个额外状态
1. 取消
异步针对的是需要消耗长时间运行的工作。在工作过程中,如果需要,我们可以取消异步的运行。系统提供了一个类CancellationToken来处理这个工作。
定义方式:
Task<T> ActionAsync(para ..., CancellationToken cancellationtoken);
调用方式:
CancellationTokenSource source = new CancellationTokenSource();
CancellationToken cancel_token = source.Token;
await ActionAsync(para, cancel_token);
需要取消时:
source.Cancel();
就可以了。
在做API时,异步中加个CancellationToken,是基本的代码礼节。
2. 进度
长时间运行,如果能给出个进度也不错。
定义方式:
Task<T> ActionAsync(para ..., IProgress<T> progress);
其中,T是需要返回的进度值,可以是各种需要的类型。
当然,我们需要实现IProgress:
public class Progress<T> : IProgress<T>
{
public Progress();
public Progress(Action<T> handler);
protected virtual void OnReport(T value);
public event EventHandler<T> ProgressChanged;
}
IProgress<T>通过回调来发送进度值,引发捕获并处理。
全文完。
这篇文章是对前一篇文章的补充和扩展。所以,要两篇一起看,才更好。
![]() |
微信公众号:老王Plus 扫描二维码,关注个人公众号,可以第一时间得到最新的个人文章和内容推送 本文版权归作者所有,转载请保留此声明和原文链接 |
一文说通C#中的异步编程补遗的更多相关文章
- 一文说通C#中的异步编程
天天写,不一定就明白. 又及,前两天看了一个关于同步方法中调用异步方法的文章,里面有些概念不太正确,所以整理了这个文章. 一.同步和异步. 先说同步. 同步概念大家都很熟悉.在异步概念出来之前,我 ...
- 一文说通C#中的异步迭代器
今天来写写C#中的异步迭代器 - 机制.概念和一些好用的特性 迭代器的概念 迭代器的概念在C#中出现的比较早,很多人可能已经比较熟悉了. 通常迭代器会用在一些特定的场景中. 举个例子:有一个for ...
- .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 ...
- promise 的基本概念 和如何解决js中的异步编程问题 对 promis 的 then all ctch 的分析 和 await async 的理解
* promise承诺 * 解决js中异步编程的问题 * * 异步-同步 * 阻塞-无阻塞 * * 同步和异步的区别? 异步;同步 指的是被请求者 解析:被请求者(该事情的处理者)在处理完事情的时候的 ...
- .NET中的异步编程
开篇 异步编程是程序设计的重点也是难点,还记得在刚开始接触.net的时候,看的是一本c#的Winform实例教程,上面大部分都是教我们如何使用Winform的控件以及操作数据库的实例,那时候做的基本都 ...
随机推荐
- 某cms代码审计
前言 前几个礼拜上课老师带着挖cms的洞,挖出个cookie反序列化注入漏洞,和报错注入并且提交了cnvd.昨天去找源码的时候发现它更新了一个版本,更新日志上也没说修复,就想着看看漏洞还存不存在, ...
- Scala 面向对象(十二):嵌套类
在Scala中,你几乎可以在任何语法结构中内嵌任何语法结构.如在类中可以再定义一个类,这样的类是嵌套类,其他语法结构也是一样. 嵌套类类似于Java中的内部类. Scala嵌套类的使用1 请编写程序, ...
- 李航统计学习方法(第二版)(五):k 近邻算法简介
1 简介 k近邻法的输入为实例的特征向量,对应于特征空间的点;输出为实例的类别,可以取多类.k近邻法假设给定一个训练数据集,其中的实例类别已定.分类时,对新的实例,根据其k个最近邻的训练实例的类别,通 ...
- 05 flask源码剖析之配置加载
05 Flask源码之:配置加载 目录 05 Flask源码之:配置加载 1.加载配置文件 2.app.config源码分析 3.from_object源码分析 4. 总结 1.加载配置文件 from ...
- 微信浏览器内 h5 直接唤醒 app 之 微信开放标签 wx-open-launch-app
以前微信浏览器内想要直接唤醒 app 要么接微信的应用宝要么你是腾讯的干儿子. 而在微信在2020年5月分推出了“微信开放标签”功能 wx-open-launch-app 用于微信浏览器内直接唤醒 a ...
- P2058 海港 (洛谷)
这个题复制过来真的有点恶心,懒得手打,以后再搬题面吧. 今天我双更了,AC这个题我就完成某谷春令营第一课的作业了(假的) 这个题是个双指针.非常友善.一直往里读入就可以了,遇见不是一条船的乘客输出这一 ...
- Ubuntu18.04安装Docker并部署(编译、发布、构建镜像)Asp.NetCore项目全过程笔记
环境准备:阿里云Ubuntu18.04 全新安装 一.安装Docker 1.删除旧版本并更新包索引: sudo apt-get remove docker docker-engine dock ...
- vue-cli 2.x和3.x配置移动端适配px自动转为rem
移动端适配一直都是个大问题,现在也出现了各种各样的解决方案,比如 rem, vw 百分比等,但是比较成熟的切比较容易编写的还是 rem,他是相对于根元素的 font-size 进行等比例计算的. 但是 ...
- vue的双向数据绑定实现原理(简单)
如果有人问你,学vue学到了什么,那双向数据绑定,是必然要说的. 我们都知道,在vue中,使用数据双向绑定我们都知道是v-modle实现的. 实现原理是通过Object.defineProperty的 ...
- maven项目打包到本地库 两种方式
方式一 1.项目根路径下 maven clean package 或者 maven package ,根据是否需要跳过代码中的测试代码 加上 -DskipTests 2.mvn install:ins ...
