.NET 实现并行的几种方式(一)

好久没有更新了,今天来一篇,算是《同步与异步》系列的开篇吧,加油,坚持下去(PS:越来越懒了)。

 

一、Thread 

利用Thread 可以直接创建和控制线程,在我的认知里它是最古老的技术了。因为out了、所以不再写例子了。

二、ThreadPool

由于线程的创建和销毁需要耗费大量的资源,为了提过性能、引入了线程池、即ThreadPool,ThreadPool 可隐式完成线程的创建和分配管理工作。

以下是来自MSDN的几句备注:

  线程池根据需要提供新的工作线程或 I/O 完成线程,直到其达到每个类别的最小值。 当达到最小值时,线程池可以在该类别中创建更多线程或等待某些任务完成。 从 .NET Framework 4 开始,线程池会创建和销毁工作线程以优化吞吐量,吞吐量定义为单位时间内完成的任务数。 线程过少时可能无法更好地利用可用资源,但线程过多时又可能会加剧资源的争用情况。

 直接应用 ThreadPool时、有两种应用场景:

1、将需要异步执行的方法、排入队列,当有可用线程时执行被排入队列的方法

复制代码

            // 该应用场景下 ThreadPool 提供如下两种形式的重载方法// public static bool QueueUserWorkItem(WaitCallback callBack);// public static bool QueueUserWorkItem(WaitCallback callBack, object state);// WaitCallback 为 delegate, 一个object类型的入参,没有返回值。// public delegate void WaitCallback(object state);base.SetTip(nameof(ThreadPool.QueueUserWorkItem));ThreadPool.QueueUserWorkItem((state) =>{this.SetTip("等待一秒");Thread.Sleep(1000);this.SetTip("任务执行完毕");});

复制代码

 

2、注册等待信号对象(WaitHandle)、并在其收到信号或超时时触发回调函数

复制代码

            // 该应用场景下 ThreadPool 提供了四种形式的重载方法, 下面的重载形式在我看来是最具有直观意义的// public static RegisteredWaitHandle RegisterWaitForSingleObject(//      WaitHandle waitObject, WaitOrTimerCallback callBack, object state, long millisecondsTimeOutInterval, bool executeOnlyOnce);// 其中 WaitHandle 为需要等待信号的类型 的 抽象基类,在后续随笔中会做详细介绍,在此不再多言。// 其中 WaitOrTimerCallback 为 回调函数委托// public delegate void WaitOrTimerCallback(object state, bool timedOut);// state 参数为 回调函数的传入参数// millisecondsTimeOutInterval 参数为 计时器超时周期, -1 为永不超时、即一直等待。// 对于此参数、第一次接触到的人可能有疑问、怎么还有周期? // 因为 信号可以重复接到多次、所以当每次接到信号后、或者超时后计时器都会重新计时, 所以有了周期的含义。// executeOnlyOnce, True 表示只执行一次, False 会一直等到该信号对象被取消注册,否则 只要接到信号或者超时就会触发回调函数。base.SetTip(nameof(ThreadPool.RegisterWaitForSingleObject));ThreadPool.RegisterWaitForSingleObject(this.waitObject, (state, timeout) =>{this.SetTip("++++++等待对象收到信号++++++");}, null, -1, false);ThreadPool.QueueUserWorkItem((state) =>{this.SetTip("等待一秒");Thread.Sleep(1000);this.SetTip("等待对象发出信号");this.waitObject.Set();this.SetTip("等待5秒");Thread.Sleep(5000);this.SetTip("等待对象发出信号");this.waitObject.Set();});

复制代码

 

三、Delegate.BeginInvoke

Delegate.BeginInvoke 间接的调用了线程池、从线程池中获取一个可用线程、执行当前委托所指向的函数指针所代表的方法。

复制代码

        [Tag("Delegate.BeginInvoke")]private void Demo3(){this.txtTip.SetTip("UI, Id:" + Thread.CurrentThread.ManagedThreadId);Action action = new Action(this.DelegateTest);action.BeginInvoke(null, null);action.BeginInvoke(null, null);            }private void DelegateTest(){int id = Thread.CurrentThread.ManagedThreadId;this.Dispatcher.Invoke(() =>{this.txtTip.SetTip("BeginInvoke, Id:" + id);});}

复制代码


通过 Thread.CurrentThread.ManagedThreadId 、我们也可以间接的证明 BeginInvoke 确实时在不同的线程中执行的。

当然,与之对应的是一系列的 Begin...  End...  方法对, 它们都是 IAsyncResult 系列的异步编程模型中的一份子。


在 IAsyncResult  系列的异步编程模型中,传递参数 和 获取返回值的Demo 见下:

复制代码

        [Tag("Delegate.BeginInvoke带有参数和返回值")]private void Demo4(){Func<string, string> func = new Func<string, string>(this.DelegateTest2);this.txtTip.SetTip(" 输入参数 123 ");func.BeginInvoke(" 123 ", new AsyncCallback((System.IAsyncResult result) =>{Func<string, string> tmp = result.AsyncState as Func<string, string>;if (tmp != null){string returnResult = tmp.EndInvoke(result);this.Dispatcher.Invoke(() =>{this.txtTip.SetTip(" 函数回调 结果 : " + returnResult);});}}), func);}private string DelegateTest2(string args){return args + " : Return args";}

复制代码

 

四、Task  

Task是在 .NET 4.0 中新增的,是基于任务的异步模型。它是对线程池的再次封装、使得可以更加方便的创建多种任务组合,如 顺序性的延续任务、父子任务。也可以方便的粗粒度地控制任务优先级。

1)Task.NET 4.0 中提倡的方式 

Task 对外公开了构造函数、但是微软并不建议直接使用Task构造函数去实例化对象,而是 使用 Task.Factory.StartNew();

MSDN 中的备注如下:
For performance reasons, TaskFactory's StartNew method should be the preferred mechanism for creating and scheduling computational tasks,
but for scenarios where creation and scheduling must be separated, the constructors may be used, 
and the task's Start method may then be used to schedule the task for execution at a later time.
Task 类还提供了初始化任务但不计划执行任务的构造函数。 出于性能方面的考虑,TaskFactory 的 StartNew 方法应该是创建和计划计算任务的首选机制,
但是对于创建和计划必须分开的情况,可以使用构造函数,然后可以使用任务的 Start 方法计划任务在稍后执行。

复制代码

            Task.Factory.StartNew(() =>{base.SetTip("Task.Factory.StartNew(一个参数)");}).ContinueWith((t) =>{base.SetTip(t.Id.ToString());base.SetTip(t.CreationOptions.ToString());}).ContinueWith((t) =>{base.SetTip(t.Id.ToString());base.SetTip(t.CreationOptions.ToString());});

复制代码

Task.Factory.StartNew 提供了高达16个的重载函数。
其中 Task.Factory.StartNew<TTask> 是创建带有返回值的异步任务。

以最复杂的重载为例、逐一介绍其参数
public Task<TResult> StartNew<TResult>(Func<object, TResult> function, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskScheduler scheduler);

function : 回调函数、我想没有必要做解释吧。
state : 回调函数的传入参数
CancellationToken : 用以取消Task (后续随笔会做详细介绍)
TaskCreationOptions : 指定可控制任务的创建和执行的可选行为的标志(后续随笔会做详细介绍)
TaskScheduler : 一个实例 TaskScheduler 类表示一个任务计划程序. 该值一般都是使用 TaskScheduler.Default

也就是说:
Task.Factory.StartNew(()=> { });
和 
Task.Factory.StartNew(()=> { }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default);
两种方式效果是一致的。

如果你想更精细化的控制任务、可以使用其他重载方法、传递不同参数以达到预想的目的。

 

2)Task初始化任务但并不计划执行

前文说过 Task 提供了构造函数、它提供了初始化任务,但并不去计划执行的方式。
让我们再看一下 Task 得构造函数吧,还是以最复杂的为例:
public Task(Func<object, TResult> function, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions);
其参数和 Task.Factory.StartNew 相比、 少了TaskScheduler。在性能方面MSDN提示后者会更好。

复制代码

            base.SetTip("初始化任务");Task task = new Task(() =>{base.SetTip("被计划的任务开始执行");base.SetTip("任务休眠5秒");Thread.Sleep(5000);base.SetTip("任务执行完毕");});// 为了保证能实时更新UI、看到代码执行效果、故而将代码异步执行Task.Factory.StartNew(() =>{base.SetTip("休眠两秒");Thread.Sleep(2000);base.SetTip("将任务列入执行计划");task.Start();base.SetTip("等待Task执行完毕");task.Wait();// Wait方法 会等待Task执行完毕base.SetTip("Task执行完毕");});

复制代码

 

另外再强调一点:Task.Start(), 只是将任务列入执行计划,至于任务什么时候去执行则取决于线程池中什么时候有可用线程。
Task.Factory.StartNew 也是一样的。

 

好了,Task类的介绍、到此为止,后续随笔再做详细介绍:这个强大的Task类,还有很多值得我们去探索的东西。

本随笔到此、暂告一段落。

附,Demo : http://files.cnblogs.com/files/08shiyan/ParallelDemo.zip

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/438093.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

REVERSE-PRACTICE-BUUCTF-32

REVERSE-PRACTICE-BUUCTF-32[第四章 CTF之APK章]数字壳的传说[第五章 CTF之RE章]Hello, RE[第五章 CTF之RE章]BabyAlgorithm[第五章 CTF之RE章]BabyConst[第五章 CTF之RE章]BabyLib[第五章 CTF之RE章]easy_rust[第五章 CTF之RE章]easy_go[第五章 CTF之RE章]easy_mfc[第四章 CTF…

.NET 实现并行的几种方式(二)

本随笔续接&#xff1a;.NET 实现并行的几种方式&#xff08;一&#xff09; 四、Task 3&#xff09;Task.NET 4.5 中的简易方式 在上篇随笔中&#xff0c;两个Demo使用的是 .NET 4.0 中的方式&#xff0c;代码写起来略显麻烦&#xff0c;这不 .NET 4.5提供了更加简洁的方…

redis 和 数据库mysql之间的关系

https://www.zhihu.com/question/20734566 https://www.zhihu.com/question/19660689 http://blog.csdn.net/Ideality_hunter/article/details/77621643 redis和mysql要根据具体业务场景去选型 mysql&#xff1a;数据放在磁盘redis&#xff1a;数据放在内存 redis适合放一些…

GPS/轨迹追踪、轨迹回放、围栏控制

折腾一个多月终于弄完了这个项目&#xff0c;起初都未曾接触GPS/轨迹追踪、轨迹回放、圈划围栏...等一些在百度地图或者Googel地图操作的一些业务&#xff0c;后端的业务相对来说简单点 cas单点登录&#xff0c;mongdb灵活的数据存储方式,ActiveMQ消息推送、Redis存储... 这篇…

C#.NET Thread多线程并发编程学习与常见面试题解析-1、Thread使用与控制基础

前言&#xff1a;因为平时挺少用到多线程的&#xff0c;写游戏时都在用协程&#xff0c;至于协程那是另一个话题了&#xff0c;除了第一次学习多线程时和以前某个小项目有过就挺少有接触了&#xff0c;最近准备面试又怕被问的深入&#xff0c;所以就赶紧补补多线程基础。网上已…

PWN-PRACTICE-BUUCTF-22

PWN-PRACTICE-BUUCTF-22hitcontraining_unlinkpicoctf_2018_leak_mesuctf_2018_basic pwnaxb_2019_brop64hitcontraining_unlink unlink&#xff0c;参考&#xff1a;[BUUCTF]PWN——hitcontraining_unlink # -*- coding:utf-8 -*- from pwn import * #ioprocess("./bam…

javaee, javaweb和javase的区别以及各自的知识体系

JavaSE Java SE 以前称为 J2SE。它允许开发和部署在桌面、服务器、嵌入式环境和实时环境中使用的 Java 应用程序。Java SE 包含了支持 Java Web 服务开发的类&#xff0c;并为 Java Platform&#xff0c;Enterprise Edition&#xff08;Java EE&#xff09;提供基础。 JavaE…

.NET 实现并行的几种方式(三)

在前两篇随笔中&#xff0c;先后介绍了 Thread 、ThreadPool 、IAsyncResult (即 APM系列) 、Task 、TPL (Task Parallel Library)。 写到这些笔者突然意识到 还有一个EMP系列没有写&#xff0c;在这里补充一下&#xff1a; 六、 EAP 、EAP中的典型代表是 WebClient: EAP系…

.NET异步编程之新利器——Task与Await、Async

一. FrameWork 4.0之前的线程世界     在.NET FrameWork 4.0之前&#xff0c;如果我们使用线程。一般有以下几种方式&#xff1a; 使用System.Threading.Thread 类&#xff0c;调用实例方法Start()开启一个新线程&#xff0c;调用Abort()方法来提前终止线程。使用System.T…

对比MS Test与NUnit Test框架

前言&#xff1a; 项目中进行Unit Test时&#xff0c;肯定会用到框架&#xff0c;因为这样能够更快捷、方便的进行测试。 .Net环境下的测试框架非常多&#xff0c;在这里只是对MS Test和NUnit Test进行一下比较&#xff0c; 因为这两个框架用的较多&#xff0c;也有大虾想过…

PWN-PRACTICE-BUUCTF-25

PWN-PRACTICE-BUUCTF-25wustctf2020_name_your_catciscn_2019_final_2mrctf2020_shellcode_revengezctf2016_note2wustctf2020_name_your_cat 通过数组越界覆写返回地址为后门shell的地址 from pwn import * #ioprocess(./wustctf2020_name_your_cat) ioremote(node4.buuoj.c…

使用 Github Pages 和 Hexo 搭建自己的独立博客【超级详细的小白教程】

2022-01-25 更新&#xff1a;博客新地址&#xff1a;https://www.itbob.cn/ 欢迎关注我的专栏&#xff1a;《个人博客搭建&#xff1a;HexoGithub Pages》&#xff0c;从搭建到美化一条龙&#xff0c;帮你解决 Hexo 常见问题&#xff01; 推荐阅读&#xff1a;《Hexo 博客优化…

windows程序消息机制(Winform界面更新有关)

1. Windows程序消息机制 Windows GUI程序是基于消息机制的,有个主线程维护着消息泵。这个消息泵让windows程序生生不息。 Windows程序有个消息队列&#xff0c;窗体上的所有消息是这个队列里面消息的最主要来源。这里的While循环使用了GetMessage() 这个方法,这是个阻塞方法,也…

最新主流 Markdown 编辑器推荐

Markdown &#xff0c;2004年由 John Gruberis 设计和开发&#xff0c;是一种可以使用普通文本编辑器编写的标记语言&#xff0c;通过简单的标记语法&#xff0c;它可以使普通文本内容具有一定的格式&#xff0c;以下将介绍目前比较流行的一些 Markdown 编辑器&#xff08;排名…

PWN-PRACTICE-BUUCTF-27

PWN-PRACTICE-BUUCTF-27starctf_2019_babyshellpicoctf_2018_buffer overflow 0gyctf_2020_signinbjdctf_2020_YDSneedGrirlfriendstarctf_2019_babyshell 用\x00绕过shellcode检测&#xff0c;call rdx 跳转过去执行汇编代码&#xff0c;一个\x00必执行失败 于是需要找一条机…

敏捷开发之Scrum扫盲,及敏捷开发中XP与SCRUM的区别

敏捷开发之Scrum扫盲篇 现在敏捷开发是越来越火了&#xff0c;人人都在谈敏捷&#xff0c;人人都在学习Scrum和XP... 为了不落后他人&#xff0c;于是我也开始学习Scrum&#xff0c;今天主要是对我最近阅读的相关资料&#xff0c;根据自己的理解&#xff0c;用自己的话来讲述S…

有关不蒜子访问统计无法显示的解决方法

十月初&#xff0c;不蒜子统计失效了&#xff0c;如下图&#xff1a; 进入不蒜子官网看看&#xff1a; 问题来了&#xff0c;官网写着&#xff1a;因七牛强制过期『dn-lbstatics.qbox.me』域名&#xff0c;与客服沟通无果&#xff0c;只能更换域名到『busuanzi.ibruce.info』…

SCRUM与XP区别

敏捷开发 1、敏捷的含义 敏捷开发是一种以人为核心、迭代、增量的开发方法。在敏捷开发中&#xff0c;把一个大项目分为多个相互联系&#xff0c;可独立运行的小项目&#xff0c;并分别完成&#xff0c;在此过程中软件一直处于可使用状态。 上面提到3个关键词&#xff0c;下…

Java编写程序时出现警告:Resource leak: 'xxx' is never closed 解决方案

菜鸟新手&#xff0c;学校在教Java&#xff0c;作业里面要求我们编程实现运算一个简单的程序&#xff0c;程序写好了&#xff0c;却发现冒出一个警告&#xff0c;如下图&#xff1a; 百度了一下&#xff0c;意思是申明了名为a的数据输入扫描仪&#xff08;Scanner&#xff09…

ASP.Net请求处理机制初步探索之旅 - Part 1 前奏

开篇&#xff1a;ASP.Net是一项动态网页开发技术&#xff0c;在历史发展的长河中WebForm曾一时成为了ASP.Net的代名词&#xff0c;而ASP.Net MVC的出现让这项技术更加唤发朝气。但是&#xff0c;不管是ASP.Net WebForm还是ASP.Net MVC在请求处理机制上大部分都是相同的&#xf…