《C#多线程编程实战(原书第2版)》——3.2 在线程池中调用委托

简介:

本节书摘来自华章出版社《C#多线程编程实战(原书第2版)》一书中的第3章,第3.2节,作者(美)易格恩·阿格佛温(Eugene Agafonov),黄博文 黄辉兰 译,更多章节内容可以访问云栖社区“华章计算机”公众号查看。

3.2 在线程池中调用委托

本节将展示在线程池中如何异步的执行委托。另外,我们将讨论一个叫做异步编程模型(Asynchronous Programming Model,简称APM)的方式,这是.NET历史中第一个异步编程模式。

3.2.1 准备工作

为了学习本节,你需要安装Visual Studio 2015。除此之外无需其他准备。本节的源代码放置在BookSamplesChapter3Recipe1目录中。

3.2.2 实现方式

请执行以下步骤来了解如何在线程池中调用委托:

1.启动Visual Studio 2015。新建一个C#控制台应用程序项目。

2.在Program.cs文件中加入以下using指令:


740dda60018aaa3e3f8d820d304feff66401fc0a

3.在Main方法下面加入以下代码片段:


6db22f34edc7485711a129c6c6c19354e6102c24

4.在Main方法中加入以下代码片段:


2230a1716522bf36637c8e5914e6a24b61e9c76e


cc6ae629ddaed43321b1ff9abe762e81f3499b5d

5.运行程序。

3.2.3 工作原理

当程序运行时,使用旧的方式创建了一个线程,然后启动它并等待完成。由于线程的构造函数只接受一个无任何返回结果的方法,我们使用了lambda表达式来将对Test方法的调用包起来。我们通过打印出Thread. CurrentThread.IsThreadPoolThread属性值来确保该线程不是来自线程池。我们也打印出了受管理的线程ID来识别代码是被哪个线程执行的。

然后定义了一个委托并调用BeginInvoke方法来运行该委托。BeginInvoke方法接受一个回调函数。该回调函数在异步操作完成后会被调用,并且一个用户自定义的状态会传给该回调函数。该状态通常用于区分异步调用。结果,我们得到一个实现了IAsyncResult接口的result对象。BeginInvoke立即返回了结果,当线程池中的工作者线程在执行异步操作时,仍允许我们继续其他工作。当需要异步操作的结果时,可以使用BeginInvoke方法调用返回的result对象。我们可以使用result对象的IsCompleted属性轮询结果。但是在本例子中,使用的是AsyncWaitHandle属性来等待直到操作完成。当操作完成后,会得到一个结果,可以通过委托调用EndInvoke方法,传递委托参数和IAsyncResult对象。

事实上使用AsyncWaitHandle并不是必要的。如果注释掉r.AsyncWaitHandle.WaitOne,代码照样可以成功运行,因为EndInvoke方法事实上会等待异步操作完成。调用EndInvoke方法(或者针对其他异步API的EndOperationName方法)是非常重要的,因为该方法会将任何未处理的异常抛回到调用线程中。当使用这种异步API时,请确保始终调用了Begin和End方法。

当操作完成后,传递给BeginInvoke方法的回调函数将被放置到线程池中,确切地说是一个工作者线程中。如果在Main方法定义的结尾注释掉Thread.Sleep方法调用,回调函数将不会被执行。这是因为当主线程完成后,所有的后台线程会被停止,包括该回调函数。对委托和回调函数的异步调用很可能会被同一个工作者线程执行。通过工作者线程ID可以容易地看出。

使用BeginOperationName/EndOperationName方法和.NET中的IAsyncResult对象等方式被称为异步编程模型(或APM模式),这样的方法对称为异步方法。该模式也被应用于多个.NET类库的API中,但在现代编程中,更推荐使用任务并行库(Task Parallel Library,简称TPL)来组织异步API。第4章将会讨论该主题。

相关文章
|
15天前
|
SQL 开发框架 安全
C#编程与多线程处理
【4月更文挑战第21天】探索C#多线程处理,提升程序性能与响应性。了解C#中的Thread、Task类及Async/Await关键字,掌握线程同步与安全,实践并发计算、网络服务及UI优化。跟随未来发展趋势,利用C#打造高效应用。
|
27天前
|
Java 数据库连接 调度
面试题:用过线程池吗?如何自定义线程池?线程池的参数?
字节跳动面试题:用过线程池吗?如何自定义线程池?线程池的参数?
27 0
|
9天前
|
Java 程序员 数据库
Java线程池让使用线程变得更加高效
使用一个线程需要经过创建、运行、销毁三大步骤,如果业务系统每个线程都要经历这个过程,那会带来过多不必要的资源消耗。线程池就是为了解决这个问题而生,需要时就从池中拿取,使用完毕就放回去,池化思想通过复用对象大大提高了系统的性能。线程池、数据库连接池、对象池等都采用了池化技术,下面我们就来学习下线程池的核心知识、面试重点~
48 4
Java线程池让使用线程变得更加高效
|
2月前
|
存储 算法 Java
【C/C++ 线程池设计思路】 深入探索线程池设计:任务历史记录的高效管理策略
【C/C++ 线程池设计思路】 深入探索线程池设计:任务历史记录的高效管理策略
87 0
|
7天前
|
监控 安全 Java
【多线程学习】深入探究阻塞队列与生产者消费者模型和线程池常见面试题
【多线程学习】深入探究阻塞队列与生产者消费者模型和线程池常见面试题
|
11天前
|
监控 Java 调度
Java多线程实战-从零手搓一个简易线程池(四)线程池生命周期状态流转实现
Java多线程实战-从零手搓一个简易线程池(四)线程池生命周期状态流转实现
|
11天前
|
设计模式 Java
Java多线程实战-从零手搓一个简易线程池(三)线程工厂,核心线程与非核心线程逻辑实现
Java多线程实战-从零手搓一个简易线程池(三)线程工厂,核心线程与非核心线程逻辑实现
|
11天前
|
Java 测试技术
Java多线程实战-从零手搓一个简易线程池(二)线程池实现与拒绝策略接口定义
Java多线程实战-从零手搓一个简易线程池(二)线程池实现与拒绝策略接口定义
|
11天前
|
存储 安全 Java
Java多线程实战-从零手搓一个简易线程池(一)定义任务等待队列
Java多线程实战-从零手搓一个简易线程池(一)定义任务等待队列