Python3 与 C# 并发编程之~ Net篇
NetCore并发编程
示例代码:https://github.com/lotapp/BaseCode/tree/master/netcore/4_Concurrency
先简单说下概念(其实之前也有说,所以简说下):
- 并发:同时做多件事情
- 多线程:并发的一种形式
- 并行处理:多线程的一种(线程池产生的一种并发类型,eg:异步编程)
- 响应式编程:一种编程模式,对事件进行响应(有点类似于JQ的事件)
Net里面很少用进程,在以前基本上都是线程+池+异步+并行+协程
我这边简单引入一下,毕竟主要是写Python的教程,Net只是帮你们回顾一下,如果你发现还没听过这些概念,或者你的项目中还充斥着各种Thread
和ThreadPool
的话,真的得系统的学习一下了,现在官网的文档已经很完善了,记得早几年啥都没有,也只能挖那些外国开源项目:
https://docs.microsoft.com/zh-cn/dotnet/standard/parallel-processing-and-concurrency
1.异步编程(Task)
Task的目的其实就是为了简化Thread
和ThreadPool
的代码,下面一起看看吧:
异步用起来比较简单,一般IO,DB,Net用的比较多,很多时候都会采用重试机制,举个简单的例子:
/// <summary>
/// 模拟一个网络操作(别忘了重试机制)
/// </summary>
/// <param name="url">url</param>
/// <returns></returns>
private async static Task<string> DownloadStringAsync(string url)
{using (var client = new HttpClient()){// 设置第一次重试时间var nextDelay = TimeSpan.FromSeconds(1);for (int i = 0; i < 3; i++){try{return await client.GetStringAsync(url);}catch { }await Task.Delay(nextDelay); // 用异步阻塞的方式防止服务器被太多重试给阻塞了nextDelay *= 2; // 3次重试机会,第一次1s,第二次2s,第三次4s}// 最后一次尝试,错误就抛出return await client.GetStringAsync(url);}
}
然后补充说下Task异常的问题,当你await的时候如果有异常会抛出,在第一个await处捕获处理即可
如果async
和await
就是理解不了的可以这样想:async
就是为了让await
生效(为了向后兼容)
对了,如果返回的是void,你设置成Task就行了,触发是类似于事件之类的方法才使用void,不然没有返回值都是使用Task
项目里经常有这么一个场景:等待一组任务完成后再执行某个操作,看个引入案例:
/// <summary>
/// 1.批量任务
/// </summary>
/// <param name="list"></param>
/// <returns></returns>
private async static Task<string[]> DownloadStringAsync(IEnumerable<string> list)
{using (var client = new HttpClient()){var tasks = list.Select(url => client.GetStringAsync(url)).ToArray();return await Task.WhenAll(tasks);}
}
再举一个场景:同时调用多个同效果的API,有一个返回就好了,其他的忽略
/// <summary>
/// 2.返回首先完成的Task
/// </summary>
/// <param name="list"></param>
/// <returns></returns>
private static async Task<string> GetIPAsync(IEnumerable<string> list)
{using (var client = new HttpClient()){var tasks = list.Select(url => client.GetStringAsync(url)).ToArray();var task = await Task.WhenAny(tasks); // 返回第一个完成的Taskreturn await task;}
}
一个async方法被await调用后,当它恢复运行时就会回到原来的上下文中运行。
如果你的Task不再需要上下文了可以使用:task.ConfigureAwait(false)
,eg:写个日记还要啥上下文?
逆天的建议是:在核心代码里面一种使用ConfigureAwait
,用户页面相关代码,不需要上下文的加上
其实如果有太多await在上下文里恢复那也是比较卡的,使用ConfigureAwait
之后,被暂停后会在线程池里面继续运行
再看一个场景:比如一个耗时操作,我需要指定它的超时时间:
/// <summary>
/// 3.超时取消
/// </summary>
/// <returns></returns>
private static async Task<string> CancellMethod()
{//实例化取消任务var cts = new CancellationTokenSource();cts.CancelAfter(TimeSpan.FromSeconds(3)); // 设置失效时间为3stry{return await DoSomethingAsync(cts.Token);}// 任务已经取消会引发TaskCanceledExceptioncatch (TaskCanceledException ex){return "false";}
}
/// <summary>
/// 模仿一个耗时操作
/// </summary>
/// <returns></returns>
private static async Task<string> DoSomethingAsync(CancellationToken token)
{await Task.Delay(TimeSpan.FromSeconds(5), token);return "ok";
}
异步这块简单回顾就不说了,留两个扩展,你们自行探讨:
- 进度方面的可以使用
IProgress<T>
,就当留个作业自己摸索下吧~ - 使用了异步之后尽量避免使用
task.Wait
ortask.Result
,这样可以避免死锁
Task其他新特征去官网看看吧,引入到此为止了。
2.并行编程(Parallel)
这个其实出来很久了,现在基本上都是用PLinq
比较多点,主要就是:
- 数据并行:重点在处理数据(eg:聚合)
- 任务并行:重点在执行任务(每个任务块尽可能独立,越独立效率越高)
数据并行
以前都是Parallel.ForEach
这么用,现在和Linq结合之后非常方便.AsParallel()
就OK了
说很抽象看个简单案例:
static void Main(string[] args)
{IEnumerable<int> list = new List<int>() { 1, 2, 3, 4, 5, 7, 8, 9 };foreach (var item in ParallelMethod(list)){Console.WriteLine(item);}
}
/// <summary>
/// 举个例子
/// </summary>
private static IEnumerable<int> ParallelMethod(IEnumerable<int> list)
{return list.AsParallel().Select(x => x * x);
}
正常执行的结果应该是:
1
4
9
25
64
16
49
81
并行之后就是这样了(不管顺序了):
25
64
1
9
49
81
4
16
当然了,如果你就是对顺序有要求可以使用:.AsOrdered()
/// <summary>
/// 举个例子
/// </summary>
private static IEnumerable<int> ParallelMethod(IEnumerable<int> list)
{return list.AsParallel().AsOrdered().Select(x => x * x);
}
其实实际项目中,使用并行的时候:任务时间适中,太长不适合,太短也不适合
记得大家在项目里经常会用到如Sum
,Count
等聚合函数,其实这时候使用并行就很合适
var list = new List<long>();
for (long i = 0; i < 1000000; i++)
{list.Add(i);
}
Console.WriteLine(GetSumParallel(list));
private static long GetSumParallel(IEnumerable<long> list)
{return list.AsParallel().Sum();
}
time dotnet PLINQ.dll
499999500000real 0m0.096s
user 0m0.081s
sys 0m0.025s
不使用并行:(稍微多了点,CPU越密集差距越大)
499999500000real 0m0.103s
user 0m0.092s
sys 0m0.021s
其实聚合有一个通用方法,可以支持复杂的聚合:(以上面sum为例)
.Aggregate(seed:0,func:(sum,item)=>sum+item);
稍微扩展一下,PLinq也是支持取消的,.WithCancellation(CancellationToken)
Token的用法和上面一样,就不复述了,如果需要和异步结合,一个Task.Run
就可以把并行任务交给线程池了
也可以使用Task的异步方法,设置超时时间,这样PLinq超时了也就终止了
PLinq这么方便,其实也是有一些小弊端的,比如它会直接最大程度的占用系统资源,可能会影响其他的任务,而传统的Parallel则会动态调整
任务并行(并行调用)
这个PLinq好像没有对应的方法,有新语法你可以说下,来举个例子:
await Task.Run(() =>Parallel.Invoke(() => Task.Delay(TimeSpan.FromSeconds(3)),() => Task.Delay(TimeSpan.FromSeconds(2))));
取消也支持:
Parallel.Invoke(new ParallelOptions() { CancellationToken = token }, actions);
扩充说明
其实还有一些比如数据流和响应编程没说,这个之前都是用第三方库,刚才看官网文档,好像已经支持了,所以就不卖弄了,感兴趣的可以去看看,其实项目里面有流数据相关的框架,eg:Spark
,都是比较成熟的解决方案了基本上也不太使用这些了。
然后还有一些没说,比如NetCore里面不可变类型(列表、字典、集合、队列、栈、线程安全字典等等)以及限流、任务调度等,这些关键词我提一下,也方便你去搜索自己学习拓展
先到这吧,其他的自己探索一下吧,最后贴一些Nuget库,你可以针对性的使用:
数据流:Microsoft.Tpl.Dataflow
响应编程(Linq的Rx操作):Rx-Main
不可变类型:Microsoft.Bcl.Immutable
Python3 与 C# 并发编程之~ Net篇相关推荐
- Python3 与 C# 并发编程之~进程先导篇
在线预览:http://github.lesschina.com/python/base/concurrency/1.并发编程-进程先导篇.html Python3 与 C# 并发编程之- 进程篇:h ...
- python3练习题:并发编程(21-25)
关于python3中的并发编程,经过这些天的学习,归纳如下: #practice21:多线程 线程的定义 方法一:直接Thread()构造 方法二:构造Thread的子类 #多线程的使用 from u ...
- Python3 与 C# 并发编程之~ 进程篇
上次说了很多Linux下进程相关知识,这边不再复述,下面来说说Python的并发编程,如有错误欢迎提出- 如果遇到听不懂的可以看上一次的文章:https://www.cnblogs.com/dotne ...
- 并发编程之多进程篇之四
主要知识点:互斥锁.队列和生产者消费者模型 一.互斥锁 1.进程之间数据不共享,但是共享同一套文件系统,所以访问同一个文件,或同一个打印终端,是没有问题的, 而共享带来的是竞争,竞争带来的结果就是错乱 ...
- Java-gt;Android并发编程引气入门篇
Android的并发编程,即多线程开发,而Android的多线程开发模型也是源于Java中的多线程模型. 所以本篇也会先讲一些Java中的多线程理念,再讲解具体涉及的类,最后深入Android中的并发 ...
- Python 并发编程:PoolExecutor 篇
个人笔记,如有疏漏,还请指正. 使用多线程(threading)和多进程(multiprocessing)完成常规的并发需求,在启动的时候 start.join 等步骤不能省,复杂的需要还要用 1-2 ...
- python3 asyncio_asyncio--python3未来并发编程主流、充满野心的模块
介绍 asyncio是Python在3.5中正式引入的标准库,这是Python未来的并发编程的主流,非常重要的一个模块.有一个web框架叫sanic,就是基于asyncio,语法和flask类似,使用 ...
- java并发编程艺术——基础篇
这篇文章目的是为了总结一下这段时间看<java并发编程艺术>学到的东西,尝试用自己的话说出来对java多线程的理解和使用. 一.什么是多线程,为什么要用多线程,多线程带来的挑战 多线程定义 ...
- java并发编程的艺术和并发编程这一篇就够了
java并发编程的艺术(精华提炼) 通常我们在使用编发编程时,主要目的是为了程序能够更快的处理,但是并不是说更多的线程就一定能够让程序变得足够快,有时候太多的线程反而消耗了更多的资源,反而让程序执行得 ...
最新文章
- SQL中distinct的用法(四种示例分析)
- arcgis怎么运行python_在arcgis上用python脚本(arcpy)做数据批处理
- ADO连接各种数据库
- opencv java 去干扰_java - OpenCV Java修补图像格式要求 - 堆栈内存溢出
- android 传递接口对象吗,android中Intent传递对象,需要实现Serializable接口或者Parcelable接口...
- 查看我的mysql_我的MYSQL学习心得(七) 查询
- Kongzue的APP拍照相册选择工具
- Wireshark coloring rules tips
- 【高数复盘】1.1映射与函数思维导图
- Android Studio完成音乐盒demo
- 微信小程序实现智能识别名片
- 以太坊合并后下跌22%,我们分析链上的数据看看是否能找到答
- 面试:1.C#中的委托是什么?事件是一种委托吗?
- 中小型电子商务网站架构
- 关于前端开发中的模块化理解
- 计算机选购配置项目活动,笔记本电脑选购活动计划.doc
- 浅谈Git原理和常用命令(学习笔记)
- RuntimeError: Found dtype Long but expected Float
- 农民工工地受伤是否就可以申请工伤?
- 互联网日报 | 4月28日 星期三 | 创维汽车品牌正式发布;Redmi正式进军游戏手机;网宿科技旗下云计算业务独立运营