c#异步task
概述
异步是什么?为什么需要异步?
- 使用多线程的目的其实即使为了实现异步+并行,异步:是相对同步的,同步就是一个流程安装一个流程执行完毕,异步就是在不影响主流程的执行同时,可以执行其他流程,这也就是达到了几个逻辑并行执行的效果。
- 异步编程要解决的问题就是许多耗时的io可能会阻塞线程导致cpu空转降低效率,或者一个长时间的后台任务会阻塞用户界面。通过将耗时任务异步执行来使系统有更高的吞吐量,或保持界面的响应能力。
- 同步/异步/阻塞/非阻塞/bio/nio/aio 参考
- c# 中实现异步的方式有很多种,本文主要讲解常用方案task
基本语法
1. task创建执行
public static void taskcreaterun() { // 方式1: task.run task.run(() => { messagebox.show("task.run"); }); // 方式2: task.factory.startnew task.factory.startnew(() => { messagebox.show("task.factory.startnew"); }); //方式3:new task<返回类型> task<int> t=new task<int>(() => { messagebox.show("new task"); return 1;}); t.start(); }
2. task异步方法
- 使用async关键字标记,表示该方法可以包含异步操作。
- 通常返回task或task
类型,其中t是返回值类型。 - 使用await或result关键字暂停方法执行,直到等待的异步操作完成。
- 使用await调用异步方法,方法定义必须添加async
方法定义:通常返回task或task
public static async task<string> getstringasync() { //方式1: 使用await的方法,方法定义必须添加async //return await task.run(() => //{ // return "task.fromresult 返回结果"; //}); //方式2: 使用task.fromresult return await task.fromresult("getstringasync task.fromresult 返回结果"); } public static task<string> getstringasync2() { return task.fromresult("getstringasync2 task.fromresult 返回结果"); }
方法调用:使用await或result关键字暂停方法执行,获取结果。 暂停多个异步方法 waitall、waitany、whenall。
var r= getstringasync().result; messagebox.show(await getstringasync2()); getstringasync2().wait();//同步,获取不到返回值,只适合无返回值的方法 //处理多个异步方法 task.waitall(getstringasync2(),getstringasync());//同步阻塞,所有执行完成。获取不到返回值,只适合无返回值的方法。 task.waitany(getstringasync2(),getstringasync());//同步阻塞,其中1个异步执行完成。获取不到返回值,只适合无返回值的方法。 //同步阻塞,获取到所有异步方法的返回值 task.whenall(getstringasync2(), getstringasync()).continuewith(p => { p.result.tolist().foreach(t => messagebox.show(t)); });
注意事项
- task.wait()和task.result 将异步转为同步,容易造成死锁。尽量少使用。
- 调用task.waitall的时候,会阻塞当前线程,直到所有的task都完成了。而task.whenall方法不会阻塞当前线程,而是直接返回了一个task,只有在读取这个task的result的时候,才会引起阻塞。
3. 取消异步执行cancellationtokensource
static cancellationtokensource cts = new cancellationtokensource(); static cancellationtoken token = cts.token; /// <summary> /// 取消异步方法 /// </summary> public static void taskcanceled() { task task = task.run(() => { for (int i = 0; i < 10; i++) { if (token.iscancellationrequested) { messagebox.show("任务已取消"); return; } messagebox.show($"正在执行操作:{i}"); thread.sleep(300); } messagebox.show("任务完成"); }, token); } //调用 taskcanceled(); thread.sleep(3000); cts.cancel();
4.task并行数量控制limitedconcurrencyleveltaskscheduler
-
https://www.cnblogs.com/discoverpalace/archive/2015/06/10/4567222.html
-
https://msdn.microsoft.com/zh-cn/library/system.threading.tasks.taskscheduler(v=vs.110).aspx
常见的应用场景
- 耗时io或三方服务:文件下载、日志记录、消息订阅、邮件短信发送等。
- web服务器: web 服务器通常使用多线程来处理多个客户端的请求。每个请求都由一个单独的线程处理,这样可以避免单个请求阻塞其他请求。
- 媒体播放器: 媒体播放器通常使用多线程来解码音频和视频数据。解码是一项耗时的操作,如果使用单线程进行解码,则会阻塞播放。使用多线程可以将解码和播放分开进行,从而提高播放的流畅性。
- 游戏: 游戏通常使用多线程来渲染图形、处理玩家输入和更新游戏状态。这些任务都需要大量的 cpu 时间,使用多线程可以充分利用多核 cpu 的优势,从而提高游戏的性能。
- 科学计算: 科学计算通常需要处理大量的数据,可以使用多线程来将计算任务分解成多个子任务,同时执行。这可以显著提高计算效率。
总结
task是c#中一种功能强大且易于使用的异步编程工具,它可以帮助我们开发更加响应、高效和易于维护的应用程序。
-
1、task的创建运行可以有三种方式:new task/task.factory/task.run
-
2、task的返回参数定义task<返回类型> 。获取返回值:task.result->要阻塞主流程
-
3、task线程的同步实现不仅仅可以通过runsynchronously来实现同步运行,当然还可以通过task.result/task.wait等方式来变向实现
-
4、task的wait/waitall/waitany实现阻塞等待执行结果
-
5、task的whenany、whenall、continuewith实现延续操作
-
6、cancellationtokensource实现异步任务取消
-
7、异步方法之:(async/await)实现同步和异步调用等
发表评论