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. ajax请求成功,状态却是200

    AJAX状态为200,这类状态代码表明服务器成功地接受了客户端请求.简单的来说成功发送一个AJAX请求,但是就是不进入success事件,进入error事件. $.ajax({ type:'POST' ...

  2. pod install速度慢解决方案

    相信大家已经感受到pod install速度越来越慢了,网上提供了几种解决方案,但是都没有完全解决速度慢的问题. 使用国内镜像的Specs 在pod install时使用命令pod install - ...

  3. Spring通过IOC帮我们做火鸡

    一.IOC--setter注入 1.准备dmo 首先准备一只火鸡 public class Turkey { private int id; private String name; public i ...

  4. vue脚手架安装,新建项目,打包

    1.安装node.js 从node官网下载并安装node,安装步骤很简单,只要一路“next”就可以了. 2.安装cnpm 淘宝镜像 npm install -g cnpm --registry=ht ...

  5. JSSDK制作思路

    需求:对外提供一个js的SDK.相当于在原有的原生SDK基础上包装一层方法. SDK原生的方法通过JSExport 协议可以让js调用到原生的方法.你可以写一个协议继承JSExport ,将需要对js ...

  6. Unity3d 与 Objective-C 数据交互,持续更新中

    Unity 3D是用于3D游戏编程的语言,它是一个用C\C++编写的强大的库.而在游戏中经常要接入用OC编写的SDK,这就涉及到了Unity3d 和 OC之间的数据交互.XCode是完成兼容C语言的. ...

  7. MVC参数传递

    MVC参数传递 请求参数自动类型转换 JSP页面 form class="loginForm" action="/user/getUser" method=&q ...

  8. 洛谷 题解 P1736 【创意吃鱼法】

    题目大意 给出一个 \(n \times m \ (1 \leq n, \ m \leq 2500)\) 的 \(01\) 矩阵,让你在其中找到一个最大的子矩阵使得该子矩阵除了一条对角线上的数字均为 ...

  9. k近邻聚类简介

    简介 在所有机器学习算法中,k近邻(K-Nearest Neighbors,KNN)相对是比较简单的. 尽管它很简单,但事实证明它在某些任务中非常有效,甚至更好.它可以用于分类和回归问题! 然而,它更 ...

  10. 测试开源.net 混淆器ConfuserEx

    由于公司业务需要简单的把代码加密混淆,于是了解了一下相关的工具然后打算用ConfuserEx试试. 开源地址:https://github.com/yck1509/ConfuserEx/ 下载地址:h ...