C#基础之多线程与异步
1.基本概念
多线程与异步是两个不同概念,之所以把这两个放在一起学习,是因为这两者虽然有区别,但也有一定联系。
多线程是一个技术概念,相对于单线程而言,多线程是多个单线程同时处理逻辑。例如,假如说一个人把水从A地提到B点可看作是单线程,那么如果两个人同时去做事(可以是相同的一件事,也可以是不同的一件事)就可以看作是两个线程。
异步:记得读书时学过一篇课文叫《统筹方法》,里面讲述煮茶喝的过程,如下:
比如,想泡壶茶喝。当时的情况是:开水没有;水壶要洗,茶壶、茶杯要洗;火已生了,茶叶也有了。怎么办?
办法甲:洗好水壶,灌上凉水,放在火上;在等待水开的时间里,洗茶壶、洗茶杯、拿茶叶;等水开了,泡茶喝。
办法乙:先做好一些准备工作,洗水壶,洗茶壶茶杯,拿茶叶;一切就绪,灌水烧水;坐待水开了,泡茶喝。
那么办法甲就是异步方法,办法乙就是同步方法。利用多线程就可以实现办法甲:如用A线程做“洗好水壶,灌上凉水,放在火上”,另B线程做“洗茶壶、洗茶杯、拿茶叶”,并在B线程中等待A线程执行完毕(即水开),再继续做“泡茶喝”。
上面是示例讲法,所谓的“等待”翻译成技术语言就是“阻塞”,异步与同步的区别就是看一事件中是否有阻塞,等待另一件事情的处理结果。从示例中也可以看到,异步中用到了多线程,但异步和多线程显然是两个不同的概念。
结论:异步是相对同步来说的一个目的,而多线程是实现这个目的一种技术方法。
2.Task的运用
Task是.NET Framework 4.5加入的概念,之前实现多线程是利用Thread类,在此只对Task进行学习,在实际编码中基本用Task,因为它比Thread更易理解,更易运用,更安全可靠。
下面是两者差异的一个总结:
1.task与thread对比,task相当于应用层,thread更底层,但二者是不一样的,没有隶属关系
2.task是在线程池上创建,是后台线程(主线程不会等其完成);Thread是单个线程,默认是前台线程
3.task可以直接获取返回值,thread不能直接从方法返回结果(可以使用变量来获取结果)
4.使用task.ContinueWith()方法可以继续执行其他任务。线程中无连续性,当线程完成工作时,不能告诉线程开始其他操作。 尽管可以使用Join()等待线程完成,但是这会阻塞主线程
5.task借助CancellationTokeSource类可以支持任务中的取消,当thread处于运行中时,无法取消它
6.task能方便捕捉到运行中的异常,thread在父方法中无法捕捉到异常
下面用示例代码来展示Task实现异步的基本运用:
public static void Main()
{
// Start the HandleFile method.
Task<int> task = HandleFileAsync();//可以看作是一个耗时任务 // Control returns here before HandleFileAsync returns.
// ... Prompt the user.
Console.WriteLine("Please wait patiently " +
"while I do something important."); // Do something at the same time as the file is being read.
string line = Console.ReadLine();
Console.WriteLine("You entered (asynchronous logic): " + line); // Wait for the HandleFile task to complete.
// ... Display its results.
task.Wait();//有调用.result时,这里可以省略。在没有调用.result时,一定要.wait()下,这个话题涉及到当task运行出现异常时:为什么要调用Wait或者Result?
或者一直不查询Task的Exception属性?你的代码就永远注意不到这个异常的发生,如果不能捕捉到这个异常,垃圾回收时,
抛出AggregateException,进程就会立即终止,这就是“牵一发动全身”,莫名其妙程序就自己关掉了
var x = task.Result;//其实在用Result的时候,内部会调用Wait
Console.WriteLine("Count: " + x); Console.WriteLine("[DONE]");
Console.ReadLine();
} static async Task<int> HandleFileAsync()//async与下文的await是成对出现,否则不能实现真正的异步,而是同步执行。
{
string file = @"C:\enable1.txt";//在这个文档中输入几个字符和输入1MB字符,最终输出结果会有不同,能很好的展示异步调用方式
Console.WriteLine("HandleFile enter");
int count = ; // Read in the specified file.
// ... Use async StreamReader method.
using (StreamReader reader = new StreamReader(file))
{
string v = await reader.ReadToEndAsync();
//string v = reader.ReadToEnd(); // ... Process the file data somehow.
count += v.Length; // ... A slow-running computation.
// Dummy code.
for (int i = ; i < ; i++)
{
int x = v.GetHashCode();
if (x == )
{
count--;
}
}
}
Console.WriteLine("HandleFile exit");
return count;
}
上面是task的基本运用,看看注释了解一些注意事项。下面是对ContinueWith,即连续任务的一个运用,如下:
static void Main()
{
// Call async method 10 times.
for (int i = ; i < ; i++)
{
Run2Methods(i);
}
// The calls are all asynchronous, so they can end at any time.
Console.ReadLine();
} static async void Run2Methods(int count)
{
// Run a Task that calls a method, then calls another method with ContinueWith.
int result = await Task.Run(() => GetSum(count))
.ContinueWith(task => MultiplyNegative1(task));
Console.WriteLine("Run2Methods result: " + result);
} static int GetSum(int count)
{
// This method is called first, and returns an int.
int sum = ;
for (int z = ; z < count; z++)
{
sum += (int)Math.Pow(z, );
}
return sum;
} static int MultiplyNegative1(Task<int> task)
{
// This method is called second, and returns a negative int.
return task.Result * -;
}
下面是如果想取消任务时CancellationTokenSource类的运用:
static void Main(string[] args)
{
using (var cts = new CancellationTokenSource())
{
Task task = new Task(() => { LongRunningTask(cts.Token); });
task.Start();
Console.WriteLine("Operation Performing...");
if (Console.ReadKey().Key == ConsoleKey.C)
{
Console.WriteLine("Cancelling..");
cts.Cancel();
}
Console.Read();
}
}
private static void LongRunningTask(CancellationToken token)
{
for (int i = ; i < ; i++)
{
if (token.IsCancellationRequested)
{
break;
}
else
{
Console.WriteLine(i);
}
}
}
以上是Task的基本运用。 3.总结
以上是利用Task、async、await实现异步的方法,示例三展示的是task实现任务的取消,这里不是一个异步方法,只是一个单纯的任务取消(可理解为多线程的取消)。Task本质是类似于threadPool的一个线程池,只需把要做的事丢进去,底层线程怎么分配怎么运行,编码时完全不用关心。如果是用thread类,就需要自己去控制线程的启停销毁等,控制不好就会“翻车”,而且这种“翻车”会导致出现莫名其妙的结果,甚至程序锁死,因此在实际编码中尽量使用task类。
C#基础之多线程与异步的更多相关文章
- Task C# 多线程和异步模型 TPL模型 【C#】43. TPL基础——Task初步 22 C# 第十八章 TPL 并行编程 TPL 和传统 .NET 异步编程一 Task.Delay() 和 Thread.Sleep() 区别
Task C# 多线程和异步模型 TPL模型 Task,异步,多线程简单总结 1,如何把一个异步封装为Task异步 Task.Factory.FromAsync 对老的一些异步模型封装为Task ...
- [Xcode 实际操作]八、网络与多线程-(22)使用GCD多线程技术异步下载图片
目录:[Swift]Xcode实际操作 本文将演示如何使用使用GCD多线程技术异步下载图片. Grand Central Dispatch(GCD) 是 Apple 开发的一个多核编程的较新的解决方法 ...
- 从Nginx的Web请求处理机制中剖析多进程、多线程、异步IO
Nginx服务器web请求处理机制 从设计架构来说,Nginx服务器是与众不同的.不同之处一方面体现在它的模块化设计,另一方面,也是最重要的一方面,体现在它对客户端请求的处理机制上. Web服务器和客 ...
- 重新想象 Windows 8 Store Apps (44) - 多线程之异步编程: 经典和最新的异步编程模型, IAsyncInfo 与 Task 相互转换
[源码下载] 重新想象 Windows 8 Store Apps (44) - 多线程之异步编程: 经典和最新的异步编程模型, IAsyncInfo 与 Task 相互转换 作者:webabcd 介绍 ...
- 重新想象 Windows 8 Store Apps (45) - 多线程之异步编程: IAsyncAction, IAsyncOperation, IAsyncActionWithProgress, IAsyncOperationWithProgress
[源码下载] 重新想象 Windows 8 Store Apps (45) - 多线程之异步编程: IAsyncAction, IAsyncOperation, IAsyncActionWithPro ...
- c# 中的多线程和异步
前言: 1.异步和多线程有区别吗? 答案:多线程可以说是实现异步的一种方法方法,两者的共同目的:使主线程保持对用户操作的实时响应,如点击.拖拽.输入字符等.使主程序看起来实时都保持着等待用户响应的状态 ...
- 第一章 管理程序流(In .net4.5) 之 实现多线程和异步处理
1. 概述 本章主要讲解.net4.5如何实现多线程和异步处理的相关内容. 2. 主要内容 2.1 理解线程 ① 使用Thread类 public static class Program { ...
- C# Socket基础(一)之启动异步服务监听
本文主要是以代码为主..NET技术交流群 199281001 .欢迎加入. //通知一个或多个正在等待的线程已发生事件. ManualResetEvent manager = new ManualRe ...
- Android Learning:多线程与异步消息处理机制
在最近学习Android项目源码的过程中,遇到了很多多线程以及异步消息处理的机制.由于之前对这块的知识只是浅尝辄止,并没有系统的理解.但是工程中反复出现让我意识到这个知识的重要性.所以我整理出这篇博客 ...
随机推荐
- 《Windows内核安全与驱动开发》 3.2 内存与链表
<Windows内核安全与驱动开发>阅读笔记 -- 索引目录 <Windows内核安全与驱动开发> 3.2 内存与链表 1. 尝试生成一个链表头并将其初始化. 2. 尝试向内存 ...
- 浅谈css样式之list-type
在我们的工作学习中,大多数人使用列表标签的时候总一般的选择是把list-type设置成none.不过可能很多人对于这个属性的细节并没有很深的了解.甚至会把list-type和list-type-sty ...
- ThinkPHP5入门(基础篇)
ThinkPHP是一个快速.简单的基于MVC和面向对象的轻量级PHP开发框架,自2006年诞生以来一直秉承简洁实用的设计原则,在保持出色的性能和至简代码的同时,尤其注重开发体验和易用性,并且拥有众多的 ...
- v-bind和v-model的本质区别和作用域
每篇一句 一场寂寞凭谁诉.算前言,总轻负. Vue视图数据展示方式和彼此的区别: {{插值表达式}} {{}}插值表达式里面 只能写表达式,不能写语句 文本输出,不会解析标签 不能作用在标签的属性上, ...
- DRF Django REST framework 之 解析器(二)
引入 Django Rest framework帮助我们实现了处理application/json协议请求的数据,如果不使用DRF,直接从 request.body 里面拿到原始的客户端请求的字节数据 ...
- git配置文件—— .gitattributes
目录 .gitattributes 文档 1. gitattributes文件以行为单位设置一个路径下所有文件的属性,格式如下: 2. 在gitattributes文件的一行中,一个属性(以text属 ...
- react-native测试安装
!!!注意!!!:init命令默认会创建最新的版本,而目前最新的0.45及以上版本需要下载boost等几个第三方库编译.这些库在国内即便翻墙也很难下载成功,导致很多人无法运行iOS项目!!!中文网在论 ...
- HDU1944 S-NIM(多个NIM博弈)
Arthur and his sister Caroll have been playing a game called Nim for some time now. Nim is played as ...
- Android Studio 3.0下创建menu布局文件的图例
当开始一个android app的时候,android studio项目中没有看到menu文件夹:如下所示: 当要添加一个按钮时,很多文档上都会说,通过在项目的 res/menu 目录中新增一个 XM ...
- linux需要了解的网络基础知识
第1章 网络命令 1.1 用户模式下的命令 1.1.1 enable切换到特权模式 Router>enable Router# 特权模式 Router# Router# 1.2 特权模式下的命令 ...