async 和 await 出现在C# 5.0之后,关系是两兄弟,Task是父辈,Thread是爷爷辈,这就是.net 多线程处理的东西,具体包括 创建线程,线程结果返回,线程中止,线程中的异常处理

1 线程创建的几个方式

 static void Main(string[] args)
{
new Thread(NewThread).Start();//这里需要注意:创建一个 new Thread()的实例的时候,需要手动调用它的Start()去启动这个实例,
//对于Task来说StartNew和Run的同时,既会创建新的线程,又会自动启动这个线程
Task.Factory.StartNew(NewThread);
Task.Run(new Action(NewThread));
}
public static void NewThread()
{
Console.WriteLine("我是一个New线程!");
}

2 使用线程池

        //线程的创建是比较耗费资源的一件事情,.net提供了线程池来帮助创建和管理线程,Task默认会直接使用线程池
//但是Thread不会,如果不使用Task,又想使用线程池,可以使用ThreadPool类 static void Main(string[] args)
{
Console.WriteLine("我是主线程:ThreadId为{0}", Thread.CurrentThread.ManagedThreadId);
ThreadPool.QueueUserWorkItem(NewThread);
Console.ReadKey();
}
public static void NewThread(object data)
{
Console.WriteLine("我是一个New线程,线程Id是{0}", Thread.CurrentThread.ManagedThreadId);
Console.ReadKey();
}

3 传入参数

 //传入参数
static void Main(string[] args)
{
new Thread(NewThread).Start("arg1");//没有匿名委托之前只能这样传入一个参数
//有了匿名委托之后,可以传入多个参数
new Thread(delegate()
{
NewThread2("arg1", "arg2", "arg3");
}).Start(); //Lambda匿名委托
new Thread(() =>
{
NewThread2("arg1", "arg2", "arg3");
}).Start();
}
public static void NewThread()
{
Console.WriteLine("我是一个New线程!");
}
public static void NewThread2(string arg1, string arg2, string arg3)
{
Console.WriteLine("我是一个New线程!");
}

4 返回值

        //返回值
//Thread这玩意是没有返回值的,但是高级的Task可以
static void Main(string[] args)
{
var str = Task.Run<string>(() =>
{
return DateTime.Now.ToString();
});
}

5 线程之间数据共享

        //线程之间共享数据问题(这种存在问题:如果第一个线程还没来得及把_isOK设置为True,第二个线程就进来了,这样在多线程情况下,结果不可预知,这就是线程不安全)
private static bool _isOK = false;
static void Main(string[] args)
{
new Thread(DoOk).Start();
Task.Factory.StartNew(DoOk);
Task.Run(() =>
{
DoOk();
}); Task.Run(new Action(DoOk));
} static void DoOk()
{
if (!_isOK)
{
Console.WriteLine("OK");
_isOK = true;
Console.ReadKey();
}
}

6 独占锁

 //解决上面线程不安全的问题就要用到锁(锁的类型有 读写锁,独占锁,互斥锁)
//独占锁
private static bool _isOK = false;
private static object _lock = new object();
static void Main(string[] args)
{
new Thread(DoOk).Start();
Task.Factory.StartNew(DoOk);
Task.Run(() =>
{
DoOk();
}); Task.Run(new Action(DoOk));
} static void DoOk()
{
lock (_lock)//独占锁,加上锁之后,被锁的代码在同一个时间内,只允许一个线性进行访问,
//其他线程会被阻塞排队,只有这个线程被释放之后,其他线程才能执行被锁的代码,因为这时候,之前的线程已经访问完毕,锁已经被释放
{
if (!_isOK)
{
Console.WriteLine("OK");
_isOK = true;
Console.ReadKey();
}
}
}

7 线程量(信号量)

        //SemaphoreSlim 可以控制对某一段代码或者对某个资源访问的线程的数量,超过这个数量其他线程就得等待,等可以访问的数量的线程访问完之后,其他线程才可以继续访问,
//跟锁的原理相似,但不是独占的,可以允许一定数量的线程同时访问 static SemaphoreSlim _sem = new SemaphoreSlim();
static void Main(string[] args)
{
for (int i = ; i <= ; i++)
{
//new Thread(() =>
//{
// Entry(i);
//}).Start();
new Thread(Entry).Start(i);
}
}
static void Entry(object id)
{
Console.WriteLine(id + "开始排队...");
_sem.Wait();
Console.WriteLine(id + "开始执行...");
Thread.Sleep( * (int)id);
Console.WriteLine(id + "执行完毕,离开");
_sem.Release();
Console.ReadKey();
}

8 捕获异常

a:

 //使用Thread 线程的异常处理(其他线程的异常,主线程能捕获到么?)
static void Main(string[] args)
{
try
{
new Thread(Entry).Start();
}
catch (Exception ee)
{
//这里其他线程的异常是捕获不到的
Console.WriteLine("捕获到异常!");
}
Console.ReadKey();
}
static void Entry()
{
throw null;
}

b:

    static void Main(string[] args)
{
try
{
var task = Task.Run(() =>
{
Entry();
});
task.Wait();//调用这句话之后主线程才能捕获task里面的异常 //对于有返回值的Task,接收了它的返回值就不需要再调用Wait(),Entry2()里面的异常有可以捕获到
var task2 = Task.Run(() =>
{
return Entry2();
});
var name = task2.Result;
}
catch (Exception)
{ Console.WriteLine("捕获到异常!");
Console.ReadKey();
}
}
static void Entry()
{
throw null;
}
static string Entry2()
{
throw null;
}

前面是铺垫,现在进入本文主题

        static void Main(string[] args)
{
Test2();//这个方法其实多余,本来可以直接写 await Test2(); 但是因为控制台入口方法不支持await
Console.WriteLine("当前线程Id" + Thread.CurrentThread.ManagedThreadId);
Console.ReadKey();
}
//方法上打上async关键字,就可以用await调用其他打上async的方法了
//await后面的方法将在另外一个线程中执行
//返回值前面加上 async,方法里面就可以用 await 了
static async Task Test()
{
await Test2();
}
static async Task Test2()
{
//.net 4.5 才有Delay
await Task.Delay();
Console.WriteLine("当前线程Id:" + Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("进入其他线程");
}

注意:await不会开启新的线程,当前线程一直往下走,直到遇到async方法,这个方法内部会调用 Task.Run或者Task.Factory.StartNew开启新的线程

也就是说方法如果不是 async,我们需要自己手动去创建Task,才会真正创建线程

  static void Main(string[] args)
{
Console.WriteLine("当前线程MainId" + Thread.CurrentThread.ManagedThreadId);
Test();
Console.ReadKey();
} static async Task Test()
{
Console.WriteLine("当前线程TestId" + Thread.CurrentThread.ManagedThreadId);
var name = Test2();//这里没有用await,所以下面的代码可以继续执行
Console.WriteLine("结束调用Test2," + Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("获取Test2的返回值" + await name + "Id:" + Thread.CurrentThread.ManagedThreadId); } static async Task<string> Test2()
{
Console.WriteLine("当前线程Test2Id" + Thread.CurrentThread.ManagedThreadId);
return await Task.Run(() =>
{
Thread.Sleep();
Console.WriteLine("当前线程Test22Id" + Thread.CurrentThread.ManagedThreadId);
return "MyName";
});
}

由上可以看出:

await 并不是针对async,而是针对方法返回的Task,所以所有的 async方法都必须返回Task,所以同样可以在Task前面加await,这也是告诉编译器需要等这个Task的返回值或者等这个Task执行完毕之后才能继续走下去

加上await关键字之后,后面的代码会被挂起等待,直到task执行完毕有返回值的时候才能继续向下执行,这一段时间主线程会处于挂起状态,

 static void Main(string[] args)
{
Console.WriteLine("当前线程MainId" + Thread.CurrentThread.ManagedThreadId);
//Test(); var task = Task.Run(() =>
{
Test3();
}); task.GetAwaiter().GetResult();
Console.WriteLine("主线程");
Console.ReadKey();
}
static void Test3()
{
Console.WriteLine("新开进程");
}

Task.GetAwait()方法会给我们返回一个awaitable的对象,通过调用这个对象的GetResult方法就会挂起主线程

当然也有例外,比如在调用Task.GetAwait()之前,主线程已经执行完了

.net的 async 和 await的更多相关文章

  1. [译] C# 5.0 中的 Async 和 Await (整理中...)

    C# 5.0 中的 Async 和 Await [博主]反骨仔 [本文]http://www.cnblogs.com/liqingwen/p/6069062.html 伴随着 .NET 4.5 和 V ...

  2. 探索c#之Async、Await剖析

    阅读目录: 基本介绍 基本原理剖析 内部实现剖析 重点注意的地方 总结 基本介绍 Async.Await是net4.x新增的异步编程方式,其目的是为了简化异步程序编写,和之前APM方式简单对比如下. ...

  3. Async和Await异步编程的原理

    1. 简介 从4.0版本开始.NET引入并行编程库,用户能够通过这个库快捷的开发并行计算和并行任务处理的程序.在4.5版本中.NET又引入了Async和Await两个新的关键字,在语言层面对并行编程给 ...

  4. 异步方法的意义何在,Async和await以及Task的爱恨情仇,还有多线程那一家子。

    前两天刚感受了下泛型接口的in和out,昨天就开始感受神奇的异步方法Async/await,当然顺路也看了眼多线程那几个.其实多线程异步相关的类单个用法和理解都不算困难,但是异步方法Async/awa ...

  5. 多线程之异步编程: 经典和最新的异步编程模型,async与await

    经典的异步编程模型(IAsyncResult) 最新的异步编程模型(async 和 await) 将 IAsyncInfo 转换成 Task 将 Task 转换成 IAsyncInfo 示例1.使用经 ...

  6. 浅谈async、await关键字 => 深谈async、await关键字

    前言 之前写过有关异步的文章,对这方面一直比较弱,感觉还是不太理解,于是会花点时间去好好学习这一块,我们由浅入深,文中若有叙述不稳妥之处,还请批评指正. 话题 (1)是不是将方法用async关键字标识 ...

  7. 使用 Async 和 Await 的异步编程(C# 和 Visual Basic)[msdn.microsoft.com]

    看到Microsoft官方一篇关于异步编程的文章,感觉挺好,不敢独享,分享给大家. 原文地址:https://msdn.microsoft.com/zh-cn/library/hh191443.asp ...

  8. 【转】【C#】C# 5.0 新特性——Async和Await使异步编程更简单

    一.引言 在之前的C#基础知识系列文章中只介绍了从C#1.0到C#4.0中主要的特性,然而.NET 4.5 的推出,对于C#又有了新特性的增加--就是C#5.0中async和await两个关键字,这两 ...

  9. C#基础系列——异步编程初探:async和await

    前言:前面有篇从应用层面上面介绍了下多线程的几种用法,有博友就说到了async, await等新语法.确实,没有异步的多线程是单调的.乏味的,async和await是出现在C#5.0之后,它的出现给了 ...

  10. C# Async与Await的使用

    这个是.NET 4.5的特性,所以要求最低.NET版本为4.5. 看很多朋友还是使用的Thread来使用异步多线程操作,基本上看不见有使用Async.Await进行异步编程的.各有所爱吧,其实都可以. ...

随机推荐

  1. Paxos算法(转)

    Paxos算法的难理解与算法的知名度一样令人敬仰,从我个人的经历而言,难理解的原因并不是该算法高深到大家智商不够,而在于Lamport在表达该算法时过于晦涩且缺乏一个完整的应用场景.如果大师能换种思路 ...

  2. How to get FlowLayoutPanel.AutoSize to work with FlowBreak

    have a problem with a FlowLayoutPanel and I don't know how to solve it. I'm placing two FlowLayoutPa ...

  3. bzoj 1226 [SDOI2009]学校食堂Dining(状压DP)

    Description 小F 的学校在城市的一个偏僻角落,所有学生都只好在学校吃饭.学校有一个食堂,虽然简陋,但食堂大厨总能做出让同学们满意的菜肴.当然,不同的人口味也不一定相同,但每个人的口味都可以 ...

  4. 如何使用 RDP 或 SSH 连接到 Azure 虚拟机

    使用 RDP 或 SSH 连接到 Azure 虚拟机 本文简要概述了如何使用远程桌面控制协议 (RDP) 或安全外壳(Secure Shell,SSH)客户端登录 Azure 虚拟机.它还包括要求和故 ...

  5. POJ1502: MPI Maelstrom

    红果果的dijstra算法应用,这里采用邻接表存储图 小插曲:while(scanf("%d",&n))提交时内存超限,改成while(scanf("%d&quo ...

  6. Codeforces Round #226 (Div. 2)B. Bear and Strings

    /* 题意就是要找到包含“bear”的子串,计算出个数,需要注意的地方就是不要计算重复. */ 1 #include <stdio.h> #include <string.h> ...

  7. CodeForces 540E - Infinite Inversions(离散化+树状数组)

    花了近5个小时,改的乱七八糟,终于A了. 一个无限数列,1,2,3,4,...,n....,给n个数对<i,j>把数列的i,j两个元素做交换.求交换后数列的逆序对数. 很容易想到离散化+树 ...

  8. 数据库概述、mysql-5.7.11-winx64.zip 的下载、安装、配置和使用(windows里安装)图文详解

    本博文的主要内容有 .数据库的概述 .mysql-5.7.11-winx64.zip 的下载    .mysql-5.7.11-winx64.zip 的安装 .mysql-5.7.11-winx64. ...

  9. Robotium学习笔记一

    一. 重签名问题 1.从手机Pull所需的apk通过压缩工具删除META-INF目录 2.通过以下命令行进行签名 >jarsigner -keystore "C:\Documents ...

  10. 如何用jQuery实现在鼠标滚动后导航栏保持固定

    要实现如下效果,鼠标滚动后,上方导航栏置顶固定 关键html代码: <div class="header-bottom"> <div class="co ...