并发事件:使用AsyncEnumerator简化APM

目录

使用 AsyncEnumerator 类

AsyncEnumerator 的体系结构

使用 Wait 和 Inbox 计数器

线程安全变形

了解更多信息

在上期专栏 (并发事件: 通过 C# 简化 APM) 中,,我讲述了一些有关如何使用新的 C# 语言功能( 匿名方法、lambda 表达式和迭代器)简化异步编程的理念。在专栏最后,我说明了如何借助 C# 迭代器 使用同步编程模型完成异步编程。图 1 显示了示例迭代器。不过,仅使用常规的 C# foreach 语句是无 法执行迭代器的代码的,因为此代码始终由调用 foreach 的线程执行,并且是连续执行,不会暂停来完 成异步 I/O 操作。

在本期专栏中,我将介绍我的 AsyncEnumerator 类,它可以智能地驱动迭代器,使不同的线程池线程 能够在不同的时间执行代码,我可以确保迭代器只有在完成异步 I/O 操作后才会执行下一次迭代。此外 ,我还会介绍 AsyncEnumerator 类的体系结构及其工作原理。

使用 AsyncEnumerator 类

下面是 AsyncEnumerator 类的定义:

public class AsyncEnumerator {
  // Methods called by code outside of the iterator
  public AsyncEnumerator();
  public void Execute(IEnumerator<Int32> enumerator);
  // Methods called by code inside the iterator
  public AsyncCallback End();
  public IAsyncResult DequeueAsyncResult();
}

AsyncEnumerator 类的用法相当简单。首先,我们来介绍如何实现您的迭代器成员,然后再介绍如何 调用。

将迭代器成员定义为可以接受所需的任何参数,并添加一个附加参数,该参数是对 AsyncEnumerator 对象的引用。返回 Int32 集合时您的迭代器成员必须设为原型;换句话说,它的返回类型必须是 IEnumerator<Int32>。

然后,在迭代器成员内部,通过调用相应的 BeginXxx 方法启动每个异步操作。您知道,如果调用 BeginXxx 方法,则必须将完成异步操作时应调用的方法的名称传递给它。

您可以调用 AsyncEnumerator 对象的 End 方法,而不需要定义自己的方法。End 方法会返回一个 AsyncCallback 代理,此代理标识在 AsyncEnumerator 类中定义的私有方法。因此,每个异步操作完成 时,AsyncEnumerator 对象中的代码都会得到通知。然后,此代码会将已完成的操作的 IAsyncResult 对 象放到 List<IAsyncResult> 对象(我称它为 inbox,即收件箱)中。

在您的代码中,在调用 BeginXxx 方法之后,放置一个 yield return 语句,用于返回排队等候的异 步操作数。在图 1 中,因为我只调用了一个 BeginXxx 方法 (BeginRead),所以 yield return 语句返 回值 1。yield return 语句将暂停您的迭代器方法,并停止执行其中的代码。

图 1 C# 迭代器

private static IEnumerator<Int32> ApmPatternWithIterator(
  AsyncEnumerator ae, String pathname) {
  using (FileStream fs = new FileStream(pathname, FileMode.Open,
    FileAccess.Read, FileShare.Read, 8192, FileOptions.Asynchronous)) {
    Byte[] data = new Byte[fs.Length];
    fs.BeginRead(data, 0, data.Length, ae.End(), null);
    yield return 1;
    Int32 bytesRead = fs.EndRead(ae.DequeueAsyncResult());
    ProcessData(data);
  }
}

稍后,我会提供一些让 yield return 语句返回非 1 值的其他示例,但对于许多应用程序而言,还是 返回 1 比较合适。在 yield return 语句中指定的数字用于告知 AsyncEnumerator 对象需要完成多少个 异步操作才能恢复迭代器的执行。因此,当迭代器暂停时,您启动的所有异步操作都会继续完成。完成每 个异步操作后,AsyncEnumerator 的收件箱中都会增加一个条目。当收件箱中的项目数等于您在 yield return 语句中指定的数字时,AsyncEnumerator 对象将恢复迭代器的执行,并允许继续执行其代码。

时间: 2024-12-23 18:31:21

并发事件:使用AsyncEnumerator简化APM的相关文章

并发事件: 通过C#简化APM

目录 匿名方法和 lambda 表达式 foreach 语句 迭代器 异步编程 我曾一直赞扬异步编程模型 (APM) 的优点,强调异步执行 I/O 密集型操作是生产高响应和可伸 缩应用程序及组件的关键.这些目标是可以达成的,因为 APM 可让您使用极少量的线程来执行大量的工 作,而无需阻止任何线程.遗憾的是,使用 APM 构建典型的应用程序或组件有些难度,因此许多程序员 不愿意去做. 有几个因素使得 APM 难以实现.首先,您需要避免状态数据驻留于线程的堆栈上, 因为线程堆栈上的数据不能迁移到其

并发事件: ReaderWriterGate锁

有一天,我正在忙于一个咨询项目,忽然碰到了一个以前从未碰到过的线程同步问题.该公司正在创 建一个 Web 服务,并且服务器收到的客户端请求几乎均需要以只读方式存取某些共享数据. 有时,还会 收到需要修改共享数据的请求,同时我们需要使这些数据保持同步.这种情况听起来非常适合采用读写锁 然而,经过对项目的更深入研究,我了解到该公司的要求有一个不寻常的地方:当服务器接收到 Web 服务请求并且锁的状态为写时,该锁持续极长的一段时间.而当写线程修改共享数据时,要读这些数据的 其他 Web 服务请求需要进

线程同步工具(三)等待多个并发事件完成

声明:本文是< Java 7 Concurrency Cookbook>的第三章, 作者: Javier Fernández González 译者:郑玉婷 等待多个并发事件完成 Java并发API提供这样的类,它允许1个或者多个线程一直等待,直到一组操作执行完成. 这个类就是CountDownLatch类.它初始一个整数值,此值是线程将要等待的操作数.当某个线程为了想要执行这些操作而等待时, 它要使用 await()方法.此方法让线程进入休眠直到操作完成. 当某个操作结束,它使用countD

并发事件: 实现CLR异步编程模型

通常 I/O 操作的特点是速度慢.不可预见.当应用程序执行同步 I/O 操作时,基本上会放弃对正在 完成实际工作的设备的控制.例如,如果应用程序调用 StreamRead 方法从 FileStream 或 NetworkStream 读取某些字节,我们无法预计该方法需要多长时间才能返回.如果正在被读取的文件位于 本地硬盘上,那么 Read 操作可能会立即返回.如果存储文件的远程服务器脱机,则 Read 方法可能会等 待几分钟,然后超时并引发异常.在此期间,发出同步请求的线程会被占用.如果该线程是

你可能不知道的陷阱:C#委托和事件的困惑

一. 问题引入          通常,一个C语言学习者登堂入室的标志就是学会使用了指针,而成为高手的标志又是"玩转指针".指针是如此奇妙,通过一个地址,可以指向一个数,结构体,对象,甚至函数.最后的一种函数,我们称之为"函数指针"(和"指针函数"可不一样!)就像如下的代码: int func(int x); /* 声明一个函数 */ int (*f) (int x); /* 声明一个函数指针 */ f=func; /* 将func函数的首地址赋

并发与实例上下文模式: WCF服务在不同实例上下文模式下的并发表现

由于WCF的并发是针对某个封装了服务实例的InstanceContext而言的,所以在不同的实例上下文模式下,会表现出不同的并发行为.接 下来,我们从具体的实例上下文模式的角度来剖析WCF的并发,如果对WCF实例上下文模式和实例上下文提供机制不了解的话,请参阅<WCF 技术剖析(卷1)>第9章. 在<实践重于理论>一文中,我写一个了简单的WCF应用,通过这个应用我们可以很清楚了监控客户端和服务操作的执行情况下.借此 ,我们可以和直观地看到服务端对于并发的服务调用请求,到底采用的是并

进程、线程知识点总结和同步(消费者生产者,读者写者三类问题)、互斥、异步、并发、并行、死锁、活锁的总结

进程和程序: 进程:是个动态的概念,指的是一个静态的程序对某个数据集的一次运行活动,而程序是静态的概念,是由代码和数据组成的程序块而已. 进程5大特点:动态性,并发性,独立运行性,异步性,和结构化的特性. 在多道程序环境下,程序不能独立运行,操作系统所有的特征都是基于进程而体现的,只有进程可以在系统中运行,程序运行必须有进程才行.进程是操作系统里资源分配的基本单位,也是独立运行的基本单位,具有动态的特点,暂时出现的特点,而且一个进程产生之后,可以再次生成多个进程出来.也可以多个进程并发执行,也可

李飞飞力赞论文:描述视频密集事件新模型 !(附论文)

前几日李飞飞发了一条推文:   推文内容: 大意为:我的学生最近的论文被TechCrunch网站选为"计算机视觉最前沿的十篇论文"之一,我真是为它们感到骄傲.继Imagenet后,计算机视觉仍然在不断突破我们的想象力. 既然是大神李飞飞的得意门生,必是值得一读的大作.其实这篇论文早在今年5月就已公布,不少知乎网友也纷纷给出了自己的解读.在这篇文章中,第一部分为论文的摘要及引言翻译,第二部分为解读(不代表本文观点),希望对你有所帮助. 若需参看原文,请查阅文末链接. 摘要 大多数视频都包

并发导论

写在前面的话  由于之前工作中的疏忽,在使用Java多线程并发的时候出了问题,遂决心全面学习并发相关知识.写作本文的意图只是希望在写作过程中把想不清楚或是一时无法掌握的地方反复揣摩记录下来.写作本文参考的各种资料较多,抱歉的是文末的参考文献中对一些叫不上名字或没有出处的资料文献并未列举出来.由于本人是初入职场的菜鸟,更是并发的门外汉,文中关于并发以及其他软硬件.程序设计语言的论据也许不够客观甚至不够正确.对于这些问题还请大家不吝指教,欢迎讨论,望共同学习进步. 1 并发 很久很久以前是没有并发这