《C#并发编程经典实例》—— 超时

声明:本文是《C#并发编程经典实例》的样章,感谢图灵授权并发编程网站发布样章,禁止以任何形式转载此文。

问题
我们希望事件能在预定的时间内到达,即使事件不到达,也要确保程序能及时进行响应。
通常此类事件是单一的异步操作(例如,等待 Web 服务请求的响应)。

解决方案
Timeout 操 作 符 在 输 入 流 上 建 立 一 个 可 调 节 的 超 时 窗 口。 一 旦 新 的 事 件 到 达, 就 重 置 超 时 窗 口。 如 果 超 过 期 限 后 事 件 仍 没 到 达,Timeout 操 作 符 就 结 束 流, 并 产 生 一 个 包 含 TimeoutException 的 OnError 通知。

下面的代码向一个域名发出 Web 请求,并使用 1 秒作为超时值:

private void Button_Click(object sender, RoutedEventArgs e)
{
var client = new HttpClient();
client.GetStringAsync("http://www.example.com/").ToObservable()
.Timeout(TimeSpan.FromSeconds(1))
.Subscribe(
x => Trace.WriteLine(DateTime.Now.Second + ": Saw " + x.Length), ex => Trace.WriteLine(ex));
}

Timeout 非常适用于异步操作,例如 Web 请求,但它也能用于任何事件流。下面的例子在
监视鼠标移动时使用 Timeout,使用起来更加简单:

private void Button_Click(object sender, RoutedEventArgs e)
{
Observable.FromEventPattern<MouseEventHandler, MouseEventArgs>(
handler => (s, a) => handler(s, a), handler => MouseMove += handler, handler => MouseMove -= handler)
.Select(x => x.EventArgs.GetPosition(this))
.Timeout(TimeSpan.FromSeconds(1))
.Subscribe(
x => Trace.WriteLine(DateTime.Now.Second + ": Saw " + (x.X + x.Y)), ex => Trace.WriteLine(ex));
}

我移动了一下鼠标,然后停止 1 秒,得到如下结果:

16: Saw 180
16: Saw 178
16: Saw 177
16: Saw 176
System.TimeoutException: The operation has timed out.

值得注意的是,一旦向 OnError 发送 TimeoutException,整个事件流就结束了,不会继续 传来鼠标移动事件。为了阻止这种情况出现,Timeout 操作符具有重载方式,在超时发生 时用另一个流来替代,而不是抛出异常并结束流。

下面的例子,在超时之前观察鼠标移动,超时发生后进行切换,观察鼠标点击:

private void Button_Click(object sender, RoutedEventArgs e)
{
var clicks = Observable.FromEventPattern
<MouseButtonEventHandler, MouseButtonEventArgs>(
handler => (s, a) => handler(s, a), handler => MouseDown += handler, handler => MouseDown -= handler)
.Select(x => x.EventArgs.GetPosition(this));

Observable.FromEventPattern<MouseEventHandler, MouseEventArgs>(
handler => (s, a) => handler(s, a), handler => MouseMove += handler, handler => MouseMove -= handler)
.Select(x => x.EventArgs.GetPosition(this))
.Timeout(TimeSpan.FromSeconds(1), clicks)
.Subscribe(
x => Trace.WriteLine(
DateTime.Now.Second + “: Saw ” + x.X + “,” + x.Y), ex => Trace.WriteLine(ex));
}

我先移动一下鼠标,停止 1 秒,然后在两个不同的位置点击。下面的输出表明,超时发生
前鼠标移动事件在进行快速移动,超时后变成两个鼠标点击事件:

49: Saw 95,39
49: Saw 94,39
49: Saw 94,38
49: Saw 94,37
53: Saw 130,141
55: Saw 469,4

讨论
Timeout 操作符对优秀的程序来说是十分必要的,因为我们总是希望程序能及时响应,即 使外部环境不理想。它可用于任何事件流,尤其是在异步操作时。需要注意,此时内部的 操作并没有真正取消,操作将继续执行,直到成功或失败。

时间: 2024-09-20 05:20:23

《C#并发编程经典实例》—— 超时的相关文章

《C#并发编程经典实例》—— 用限流和抽样抑制事件流

声明:本文是<C#并发编程经典实例>的样章,感谢图灵授权并发编程网站发布样章,禁止以任何形式转载此文. 问题 有时事件来得太快,这是编写响应式代码时经常碰到的问题.一个速度太快的事件流可导 致程序的处理过程崩溃. 解决方案 Rx 专门提供了几个操作符,用来对付大量涌现的事件数据.Throttle 和 Sample 这两个操 作符提供了两种不同方法来抑制快速涌来的输入事件. Throttle 建立了一个超时窗口,超时期限可以设置.当一个事件到达时,它就重新开始计 时.当超时期限到达时,它就把窗口

C#并发编程经典实例--并发编程概述

来自 "C#并发编程经典实例" 优秀软件的一个关键特征就是具有并发性.过去的几十年,我们可以进行并发编程,但是难度很大.以前,并发性软件的编写.调试和维护都很难,这导致很多开发人员为图省事放弃了并发编程.新版.NET 中的程序库和语言特征,已经让并发编程变得简单多了.随着Visual Studio 2012 的发布,微软明显降低了并发编程的门槛.以前只有专家才能做并发编程,而今天,每一个开发人员都能够(而且应该)接受并发编程. 1.1 并发编程简介 首先,我来解释几个贯穿本书始终的术语

《C#并发编程经典实例》—— 转换.NET事件

声明:本文是<C#并发编程经典实例>的样章,感谢图灵授权并发编程网站发布样章,禁止以任何形式转载此文. 问题 把一个事件作为 Rx 输入流,每次事件发生时通过 OnNext 生成数据. 解决方案 Observable 类 定 义 了 一 些 事 件 转 换 器. 大 部 分 .NET 框 架 事 件 与 FromEventPattern 兼 容, 对于不遵循通用模式的事件,需要改用 FromEvent. FromEventPattern 最适合使用委托类型为 EventHandler 的事件.

《C#并发编程经典实例》—— 发送通知给上下文

声明:本文是<C#并发编程经典实例>的样章,感谢图灵授权并发编程网站发布样章,禁止以任何形式转载此文. 问题 Rx 尽量做到了线程不可知(thread agnostic).因此它会在任意一个活动线程中发出通知(例如 OnNext). 但是我们通常希望通知只发给特定的上下文.例如 UI 元素只能被它所属的 UI 线程控制, 因此,如果要根据 Rx 的通知来修改 UI,就应该把通知"转移"到 UI 线程. 解决方案 Rx 提供了 ObserveOn 操作符,用来把通知转移到其他

《C#并发编程经典实例》—— 用窗口和缓冲对事件分组

声明:本文是<C#并发编程经典实例>的样章,感谢图灵授权并发编程网站发布样章,禁止以任何形式转载此文. 问题 有一系列事件,需要在它们到达时进行分组.举个例子,需要对一些成对的输入作出响 应.第二个例子,需要在 2 秒钟的窗口期内,对所有输入进行响应. 解决方案 Rx 提 供 了 两 个 对 到 达 的 序 列 进 行 分 组 的 操 作:Buffer 和 Window.Buffer 会 留 住 到 达 的 事 件, 直 到 收 完 一 组 事 件, 然 后 会 把 这 一 组 事 件 以 一

《C#并发编程经典实例》—— Rx基础

LINQ 是 对 序 列 数 据 进 行 查 询 的 一 系 列 语 言 功 能. 内 置 的 LINQ to Objects( 基 于 IEnumerable<T>) 和 LINQ to Entities( 基 于 IQueryable<T>) 是 两 个 最 常 用 的 LINQ 提 供 者.另外还有很多提供者,并且大多数都采用相同的基本架构.查询是延后执行(lazily evaluated)的,只有在需要时才会从序列中获取数据.从概念上讲,这是一种拉取模式. 在查询过程中数据

Python中的并发编程实例_python

一.简介 我们将一个正在运行的程序称为进程.每个进程都有它自己的系统状态,包含内存状态.打开文件列表.追踪指令执行情况的程序指针以及一个保存局部变量的调用栈.通常情况下,一个进程依照一个单序列控制流顺序执行,这个控制流被称为该进程的主线程.在任何给定的时刻,一个程序只做一件事情. 一个程序可以通过Python库函数中的os或subprocess模块创建新进程(例如os.fork()或是subprocess.Popen()).然而,这些被称为子进程的进程却是独立运行的,它们有各自独立的系统状态以及

Python并发编程介绍及实例应用

关于Python并发编程的知识,本文基本介绍到位,想深入学习Python的朋友可以参考一下. Python并发简介 我们将一个正在运行的程序称为进程.每个进程都有它自己的系统状态,包含内存状态.打开文件列表.追踪指令执行情况的程序指针以及一个保存局部变量的调用栈.通常情况下,一个进程依照一个单序列控制流顺序执行,这个控制流被称为该进程的主线程.在任何给定的时刻,一个程序只做一件事情. 一个程序可以通过Python库函数中的os或subprocess模块创建新进程(例如os.fork()或是sub

实例讲解Java并发编程之闭锁_java

闭锁相当于一扇门,在闭锁到达结束状态之前,这扇门一直是关闭着的,没有任何线程可以通过,当到达结束状态时,这扇门才会打开并容许所有线程通过.它可以使一个或多个线程等待一组事件发生.闭锁状态包括一个计数器,初始化为一个正式,正数表示需要等待的事件数量.countDown方法递减计数器,表示一个事件已经发生,而await方法等待计数器到达0,表示等待的事件已经发生.CountDownLatch强调的是一个线程(或多个)需要等待另外的n个线程干完某件事情之后才能继续执行. 场景应用: 10个运动员准备赛