0 什么是异步执行
异步(asynchronous)执行他还有个 兄弟是 同步执行(Synchronous)
同步执行呢
程序只能干一件事情, 干完一件 再干一件,中间还不能打扰他,反正他也不理, 一打扰一气之下就给你个未响应 ,让你干瞪眼. 你说气不气
异步执行就不一样了
程序进化了,他智商提高了..他可以三心二用了
一个程序他可以分开干,也可给他多任务做,不比顺序执行任务
有一个非常经典例子
界面上点击按钮 下载文件
如果在同步执行的话,需要等待文件下载完,界面才可以点击,相当不人性化操作
在异步执行中呢
我可以新开一个线程去下载这玩意,让他下载完了,我再去操作下载的文件,不用干等着下载
这时候界面还可以点,不会出现卡顿的现象,极大的提高了操作性.
1 异步的实现
异步的实现也经历了好多代的演变,
现在常用的是
Task
和 Task<T>
类型 和async
和 await
关键字
任务
任务是用于实现称之为并发 Promise 模型的构造。 简单地说,它们“承诺”,会在稍后完成工作,让你使用干净的 API 与 promise 协作。
这是MSDN的解释
值的注意的是,任务并不是简单的新开一个线程,
而是在现有的进程有用的线程中休眠的进行工作,如果没有的话休眠的线程再新开线程,减少开销
中间做了一些包装.有兴趣的可以去研究一下
任务的取消(可选)
取消是异步方法实现者和异步方法使用者的选项。 如果操作允许取消,则会公开接受取消标记(CancellationToken 实例)的异步方法的重载。 按照约定,该参数命名为 cancellationToken
例如:
public Task ReadAsync(byte [] buffer, int offset, int count, CancellationToken cancellationToken)
不过值得注意的是
任务的取消是逻辑取消.
需要自己在程序中判断
如果程序中没有判断这个表示
在任务上取消也是没有用,程序还是一直跑下去的
还有一些其他操作
例如任务的进度啊Task.whenAll什么.这里就不展开了..
async/await
async 标明是异步方法(其实没太大用处,主要是用于兼容)
await 执行挂起
等待 Task 时,await
表达式的类型为 void
。 等待 Task<TResult> 时,await
表达式的类型为 TResult
。 await
表达式必须出现在异步方法的正文内。 (.NET Framework 4.5 中引入了这些语言功能)
class Program
{
static void Main(string[] args)
{
var str = TestAsync().Result;
Console.WriteLine(str);
Console.WriteLine($"{DateTime.Now.ToString("ss.fff")} 测试点一");
Console.ReadKey();
}
public static async Task<string> TestAsync()
{
var re = string.Empty;
Task.Factory.StartNew(() =>
{
Thread.Sleep(2000);
Console.WriteLine($"{DateTime.Now.ToString("ss.fff")} 测试点二");
re += $"当前任务一线程为:{Thread.CurrentThread.ManagedThreadId}";
Console.WriteLine("函数体内"+re);
});
await Task.Run(() =>
{
Thread.Sleep(1000);
Console.WriteLine($"{DateTime.Now.ToString("ss.fff")} 测试点三");
re += $"当前任务二线程为:{Thread.CurrentThread.ManagedThreadId}";
Console.WriteLine("函数体内"+re);
});
return re;
}
}
函数的输出结果
可以看出任务二 有了关键字 await 的阻塞 ,等他跑完之后才返回 re
而任务一没有阻塞 ,所以并没有等他跑完,就返回了,
虽然值返回了,但是任务还在跑 ,所以后面有继续输出
还有值得注意的Task.Resut获取结果时会阻塞线程,所以[测试点一] 这个日志当 re 输出后,才输出的
如果不需要取 Taks.Reuslt的话 ,并没有阻塞当前进程,
持续学习中..