# C# 中的Task创建指南
本文还处于草稿阶段,难免还有错误修改改正,逻辑还不是很清晰,笔者会努力完善,长期更新!
[0000] 前言
标题起得有些"大",意在集大家的力量,总结出来一份关于Task相对"正确"的知识总结,欢迎读者提出宝贵意见!本文内容来自于笔者在编码的时候种种疑问,来自于对异步编程在操作系统中实际运行过程的好奇。平时使用Task战战兢兢,既想提高效率,又怕它不受控制,到处乱来。与其这样,不如此时此刻一起来了解它神秘的面纱吧!Just do IT.
[0001] 为什么要编写异步代码
新型应用广泛使用文件和网络 I/O。 默认情况下 I/O API 一般会阻塞,导致糟糕的用户体验和硬件利用率,除非希望学习和使用富有挑战的模式。 基于任务的异步 API 和语言级异步编程模型改变了这种模型,只需了解几个新概念就可默认进行异步执行。
异步代码具有以下特点:
- 等待 I/O 请求返回的同时,可通过生成处理更多请求的线程,处理更多的服务器请求。
- 等待 I/O 请求的同时生成 UI 交互线程,并通过将长时间运行的工作转换到其他 CPU 核心,让 UI 的响应速度更快。
- 许多较新的 .NET APIs 都是异步的。
- 在 .NET 中编写异步代码很简单!
来源: https://docs.microsoft.com
[0010] 关于C#中的异步编程模式
.NET 提供了执行异步操作的三种模式:
基于任务的异步模式 (TAP) ,该模式使用单一方法表示异步操作的开始和完成。 TAP 是在 .NET Framework 4 中引入的。 这是在 .NET 中进行异步编程的推荐方法。 C# 中的 async 和 await 关键词以及 Visual Basic 中的 Async 和 Await 运算符为 TAP 添加了语言支持。 有关详细信息,请参阅基于任务的异步模式 (TAP)。
基于事件的异步模式 (EAP) ,是提供异步行为的基于事件的旧模型。 这种模式需要后缀为
Async的方法,以及一个或多个事件、事件处理程序委托类型和EventArg派生类型。 EAP 是在 .NET Framework 2.0 中引入的。 建议新开发中不再使用这种模式。 有关详细信息,请参阅基于事件的异步模式 (EAP)。异步编程模型 (APM) 模式(也称为 IAsyncResult 模式),这是使用 IAsyncResult 接口提供异步行为的旧模型。 在这种模式下,同步操作需要
Begin和End方法(例如,BeginWrite和EndWrite以实现异步写入操作)。 不建议新的开发使用此模式。 有关详细信息,请参阅异步编程模型 (APM)。
模式的比较
为了快速比较这三种模式的异步操作方式,请考虑使用从指定偏移量处起将指定量数据读取到提供的缓冲区中的Read方法:
public class MyClass
{
public int Read(byte [] buffer, int offset, int count);
}
此方法对应的 TAP 将公开以下单个 ReadAsync 方法:
public class MyClass
{
public Task<int> ReadAsync(byte [] buffer, int offset, int count);
}
对应的 EAP 将公开以下类型和成员的集:
public class MyClass
{
public void ReadAsync(byte [] buffer, int offset, int count);
public event ReadCompletedEventHandler ReadCompleted;
}
对应的 APM 将公开 BeginRead 和 EndRead 方法:
public class MyClass
{
public IAsyncResult BeginRead(
byte [] buffer, int offset, int count,
AsyncCallback callback, object state);
public int EndRead(IAsyncResult asyncResult);
}
来源: https://docs.microsoft.com
分割线,未完区域--------------------------------
[0011] 实践
使用Async
请一路Async,否则会不可控。
网络请求,文件读写时系统自带的Async方法不会创建多线程,而是使用完成端口,依靠中断来实现!
线程池中的线程分为 WorkerThread 和 CompletionPortThread .
平时我们使用的线程是WorkerThread,IO读写使用的是CompletionPortThread
1. 创建IO密集型任务
以下代码不会创建多个线程(WorkerThread),代码会在当前线程工作,且不会堵塞哦。
执行起来非常类似同步程序, 使用 await RunActionAsync(()=>{});
后,会立即执行程序
public Task RunActionAsync(Action action)
{
TaskCompletionSource<Task> source = new TaskCompletionSource<Task>(TaskCreationOptions.AttachedToParent);
Task<Task> task = source.Task;
try
{
action.Invoke();
}
catch (Exception ex)
{
source.SetException(ex);
}
source.SetResult(Task.CompletedTask);
return task;
}
2. 计算密集型任务
以下代码会创建新线程(WorkerThread),位于线程池,线程池默认最小WorkerThread为CPU核心数,CompletionPortThread为1000(实际最小值依实际运行情况而定,可手工修改)
运行时并不会立即执行Action,按照默认执行计划(TaskScheduler.Default执行,比如用for循环一堆Task.Run(async ()=> {await httpgetAsync(); echo(i); )任务,执行时你会发现i都是最后一个值
await Task.Run(()=>{});
以下代码会创建新线程(WorkerThread),在不在ThreadPool关键在于TaskCreationOptions枚举,如果为LongRunning,则直接会创建一个非线程池的线程执行任务,如果不是,则会在线程池里寻找线程,如果没有,会在线程池里新申请线程(创建一个耗时一秒),执行任务。
会立即执行Action
Task.Factory.StartNew(_ =>
{
action.Invoke();
},
null,
CancellationToken.None,
TaskCreationOptions.LongRunning,
TaskScheduler.Default)
3.一些坑
以下代码.NET Core不支持哦,请使用Task.Factory.StartNew代替
Task.Factory.FromAsync(
new Func<AsyncCallback, object, IAsyncResult>((cb, obj) => action.BeginInvoke(biz, cb, obj)),
new Action<IAsyncResult>(ar => action.EndInvoke(ar)), null)
参考
The danger of TaskCompletionSource class
了解 .NET 的默认 TaskScheduler 和线程池(ThreadPool)设置,避免让 Task.Run 的性能急剧降低
.NET 中小心嵌套等待的 Task,它可能会耗尽你线程池的现有资源,出现类似死锁的情况
.NET 中使用 TaskCompletionSource 作为线程同步互斥或异步操作的事件
定义一组抽象的 Awaiter 的实现接口,你下次写自己的 await 可等待对象时将更加方便
.NET 除了用 Task 之外,如何自己写一个可以 await 的对象?
Asynchronous I/O in C#: I/O Completion Ports
Asynchronous I/O in C#: I/O Completion Ports
Migrating Delegate.BeginInvoke Calls for .NET Core
声明
本文采用知识共享署名-非商业性使用-相同方式共享 2.5 中国大陆许可协议进行许可,发表在CSDN和博客园,欢迎读者转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接!请读者/爬虫们尊重版权
# C# 中的Task创建指南的更多相关文章
- 【手记】MTK之TASK创建及使用
首先来看看task的数据类型声明,在config\include\hal\task_config.h中对task和module类型进行了定义. /*************************** ...
- Netty中NioEventLoopGroup的创建源码分析
NioEventLoopGroup的无参构造: public NioEventLoopGroup() { this(0); } 调用了单参的构造: public NioEventLoopGroup(i ...
- Pycharm在Ubuntu14.04中的基本使用指南
前几天给大家分享了:如何在VMware虚拟机中安装Ubuntu14.04系统.今天给大家分享一下在Ubuntu14.04中如何简单的使用Pycharm.1.启动Pycharm,将进入Pycharm的启 ...
- 深入理解gradle中的task
目录 简介 定义task tasks 集合类 Task 之间的依赖 定义task之间的顺序 给task一些描述 task的条件执行 task rule Finalizer tasks 总结 深入理解g ...
- 一、neo4j中文文档-入门指南
目录 neo4j中文文档-入门指南 Neo4j v4.4 neo4j **Cypher ** 开始使用 Neo4j 1. 安装 Neo4j 2. 文档 图数据库概念 1. 示例图 2.节点 3. 节点 ...
- JVM中对象的创建过程
JVM中对象的创建过程如以下流程图中所示: 对其主要步骤进行详细阐述: 为新生对象分配内存: 内存的分配方式: 指针碰撞:假设Java堆中内存是绝对规整的,所有用过的内存放在一边,空闲的内存在另一边, ...
- C/C++中动态链接库的创建和调用
DLL 有助于共享数据和资源.多个应用程序可同时访问内存中单个DLL 副本的内容.DLL 是一个包含可由多个程序同时使用的代码和数据的库.下面为你介绍C/C++中动态链接库的创建和调用. 动态连接库的 ...
- ora-01658 :无法为表空间USERS 中的段创建INITIAL区
"CREATE INDEX "IDX_TS_BONUS_Q_201209_DS" ON "TS_BONUS_Q_201209" ("DS&q ...
- (转).NET 4.5中使用Task.Run和Parallel.For()实现的C# Winform多线程任务及跨线程更新UI控件综合实例
http://2sharings.com/2014/net-4-5-task-run-parallel-for-winform-cross-multiple-threads-update-ui-dem ...
随机推荐
- Java 前后端分离项目:微人事
本文适合刚学习完 Java 语言基础的人群,跟着本文可了解和运行项目,本示例是在 Windows 操作系统下演示. 本文作者:HelloGitHub-秦人 大家好!这里是 HelloGitHub 推出 ...
- 【数据结构】10.java源码关于LinkedHashMap
目录 1.LinkedHashMap的内部结构 2.LinkedHashMap构造函数 3.元素新增策略 4.元素删除 5.元素修改和查找 6.特殊操作 7.扩容 8.总结 1.LinkedHashM ...
- SpringMVC 三种异常处理方式
SpringMVC 三种异常处理方式 在 SpringMVC, SpringBoot 处理 web 请求时, 若遇到错误或者异常,返回给用户一个良好的错误信息比 Whitelabel Error Pa ...
- Keras(六)Autoencoder 自编码 原理及实例 Save&reload 模型的保存和提取
Autoencoder 自编码 压缩与解压 原来有时神经网络要接受大量的输入信息, 比如输入信息是高清图片时, 输入信息量可能达到上千万, 让神经网络直接从上千万个信息源中学习是一件很吃力的工作. 所 ...
- Spring源码解析之ConfigurableApplicationContext
UML图 接口的作用 从上面的UML图中,可以看到 ConfigurableApplicationContext 直接继承了 ApplicationContext, Lifecycle, Closea ...
- Minimum spanning tree for each edge(倍增LCA)
https://vjudge.net/contest/320992#problem/J 暑期训练的题. 题意:给你一个n个点,m条边的无向图.对于每一条边,求包括该边的最小生成树. 思路:首先想到求一 ...
- bzoj 2001 CITY 城市建设 cdq分治
题目传送门 题解: 对整个修改的区间进行分治.对于当前修改区间来说,我们对整幅图中将要修改的边权都先改成-inf,跑一遍最小生成树,然后对于一条树边并且他的权值不为-inf,那么这条边一定就是树边了. ...
- CodeForces 1082 F Speed Dial
题目传送门 题意:现在有n个电话号码,每个电话号码为si,拨打次数为pi. 现在有k 个快捷键,每次拨打号码之前可以先按一次快捷键,然后再输入数字,现在问输入数字次数是多少.快捷键的号码可以不在电话簿 ...
- Codeforces 898 B(拓展欧几里得)
Proper Nutrition 题意:有n元钱,有2种单价不同的商品,是否存在一种购买方式使得钱恰好花光,如果有输入任意一种方式,如果没有输出“NO” 题解:可以使用拓展欧几里得快速求解. #inc ...
- andriod开发--使用Http的Get和Post方式与网络交互通信
package com.example.a350773523.myapplication; import android.os.AsyncTask; import android.support.v7 ...