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#基础之多线程与异步的更多相关文章

  1. 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 ...

  2. [Xcode 实际操作]八、网络与多线程-(22)使用GCD多线程技术异步下载图片

    目录:[Swift]Xcode实际操作 本文将演示如何使用使用GCD多线程技术异步下载图片. Grand Central Dispatch(GCD) 是 Apple 开发的一个多核编程的较新的解决方法 ...

  3. 从Nginx的Web请求处理机制中剖析多进程、多线程、异步IO

    Nginx服务器web请求处理机制 从设计架构来说,Nginx服务器是与众不同的.不同之处一方面体现在它的模块化设计,另一方面,也是最重要的一方面,体现在它对客户端请求的处理机制上. Web服务器和客 ...

  4. 重新想象 Windows 8 Store Apps (44) - 多线程之异步编程: 经典和最新的异步编程模型, IAsyncInfo 与 Task 相互转换

    [源码下载] 重新想象 Windows 8 Store Apps (44) - 多线程之异步编程: 经典和最新的异步编程模型, IAsyncInfo 与 Task 相互转换 作者:webabcd 介绍 ...

  5. 重新想象 Windows 8 Store Apps (45) - 多线程之异步编程: IAsyncAction, IAsyncOperation, IAsyncActionWithProgress, IAsyncOperationWithProgress

    [源码下载] 重新想象 Windows 8 Store Apps (45) - 多线程之异步编程: IAsyncAction, IAsyncOperation, IAsyncActionWithPro ...

  6. c# 中的多线程和异步

    前言: 1.异步和多线程有区别吗? 答案:多线程可以说是实现异步的一种方法方法,两者的共同目的:使主线程保持对用户操作的实时响应,如点击.拖拽.输入字符等.使主程序看起来实时都保持着等待用户响应的状态 ...

  7. 第一章 管理程序流(In .net4.5) 之 实现多线程和异步处理

    1. 概述 本章主要讲解.net4.5如何实现多线程和异步处理的相关内容. 2. 主要内容 2.1 理解线程 ① 使用Thread类   public static class Program   { ...

  8. C# Socket基础(一)之启动异步服务监听

    本文主要是以代码为主..NET技术交流群 199281001 .欢迎加入. //通知一个或多个正在等待的线程已发生事件. ManualResetEvent manager = new ManualRe ...

  9. Android Learning:多线程与异步消息处理机制

    在最近学习Android项目源码的过程中,遇到了很多多线程以及异步消息处理的机制.由于之前对这块的知识只是浅尝辄止,并没有系统的理解.但是工程中反复出现让我意识到这个知识的重要性.所以我整理出这篇博客 ...

随机推荐

  1. Scrapy爬虫及案例剖析

    由于互联网的极速发展,所有现在的信息处于大量堆积的状态,我们既要向外界获取大量数据,又要在大量数据中过滤无用的数据.针对我们有益的数据需要我们进行指定抓取,从而出现了现在的爬虫技术,通过爬虫技术我们可 ...

  2. Spring Boot2 系列教程(二十九)Spring Boot 整合 Redis

    经过 Spring Boot 的整合封装与自动化配置,在 Spring Boot 中整合Redis 已经变得非常容易了,开发者只需要引入 Spring Data Redis 依赖,然后简单配下 red ...

  3. 【Python成长之路】从 零做网站开发 -- 基于Flask和JQuery,实现表格管理平台

    [写在前面] 你要开发网站?    嗯.. 会Flask吗?    什么东西,没听过... 会JQuery吗?    是python的库吗 ? 那你会什么?    我会F12打开网站 好吧,那我们来写 ...

  4. 转:Java transient关键字使用小记

    哎,虽然自己最熟的是Java,但很多Java基础知识都不知道,比如transient关键字以前都没用到过,所以不知道它的作用是什么,今天做笔试题时发现有一题是关于这个的,于是花个时间整理下transi ...

  5. STM32F4 阿波罗 库函数与C语言知识

    先聊一聊: 之前使用32都是用的库函数,但是没有理解为什么那么操作,有很多的文件我也不知道要看哪一个,感觉云里雾里,没有学清楚一件东西的感觉不太好,于是就在前几天一直跟着比较详细的视频学习.开始老师讲 ...

  6. luogu P1712 [NOI2016]区间

    题目描述 在数轴上有 n个闭区间 [l1,r1],[l2,r2],...,[ln,rn].现在要从中选出 m 个区间,使得这 m个区间共同包含至少一个位置.换句话说,就是使得存在一个 x,使得对于每一 ...

  7. 2.4G芯片SI24R1可替代NRF24L01P

    随着美金和原厂对价格的调控,NRF24L01P的价格越来越高,对终端制造的客户造成了不少的压力成本,但很多人又不原意花费更多的人力物力去重新改版. 小编今天就着重给大家介绍一款芯片,可以在不改板的情况 ...

  8. 大数据之Linux基本指令

    1:文件操作类指令 ls 是英文单词list 的简写, 其功能为列出目录的内容,是最常用的命令之一 -a all 显示指定目录下所有子目录与文件, 包含隐藏文件 -l 以列表方式显示文件的详细信息 - ...

  9. Ubuntu18.04安装openCV4.1.2

    Ubuntu18.04下安装openCV4.1.2 注意: 在整个安装过程中,包括后期QT的使用中不要出现中文路径.会很坑的. 一.下载openCV4.1.2 可以再官网进行下载https://ope ...

  10. HDU3710 Battle over Cities(最小生成树+树链剖分+倍增+线段树)

    Battle over Cities Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Othe ...