zl程序教程

您现在的位置是:首页 >  后端

当前栏目

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

c#实例经典并发编程 发送 通知 上下文
2023-09-11 14:16:13 时间

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

问题

Rx 尽量做到了线程不可知(thread agnostic)。因此它会在任意一个活动线程中发出通知(例如 OnNext)。

但是我们通常希望通知只发给特定的上下文。例如 UI 元素只能被它所属的 UI 线程控制, 因此,如果要根据 Rx 的通知来修改 UI,就应该把通知“转移”到 UI 线程。

解决方案

Rx 提供了 ObserveOn 操作符,用来把通知转移到其他线程调度器。 看下面的例子,使用 Interval,每秒钟产生一个 OnNext 通知:


Trace.WriteLine("UI thread is " + Environment.CurrentManagedThreadId); Observable.Interval(TimeSpan.FromSeconds(1))
.Subscribe(x = Trace.WriteLine("Interval " + x + " on thread " + Environment.CurrentManagedThreadId));

Interval 6 on thread 11

因为 Interval 基于一个定时器(没有指定的线程),通知会在线程池线程中引发,而不是 在 UI 线程中。要更新 UI 元素,可以通过 ObserveOn 输送通知,并传递一个代表 UI 线程 的同步上下文:


Trace.WriteLine("UI thread is " + Environment.CurrentManagedThreadId); Observable.Interval(TimeSpan.FromSeconds(1))
.Subscribe(x = Trace.WriteLine("Interval " + x + " on thread " + Environment.CurrentManagedThreadId));

ObserveOn 的另一个常用功能是可以在必要时离开 UI 线程。假设有这样的情况:鼠标一移

动,就意味着需要进行一些 CPU 密集型的计算。默认情况下,所有的鼠标移动事件都发 生在 UI 线程,因此可以使用 ObserveOn 把通知移动到一个线程池线程,在那里进行计算, 然后再把表示结果的通知返回给 UI 线程:

private void Button_Click(object sender, RoutedEventArgs e)

{

var uiContext = SynchronizationContext.Current;

Trace.WriteLine(“UI thread is ” + Environment.CurrentManagedThreadId); Observable.FromEventPattern MouseEventHandler, MouseEventArgs (

handler = (s, a) = handler(s, a), handler = MouseMove += handler, handler = MouseMove -= handler)

.Select(evt = evt.EventArgs.GetPosition(this))

.ObserveOn(Scheduler.Default)

.Select(position =

{

// 复杂的计算过程。

Thread.Sleep(100);

var result = position.X + position.Y; Trace.WriteLine(“Calculated result ” + result + ” on thread ” +

Environment.CurrentManagedThreadId);

return result;

})

.ObserveOn(uiContext)

.Subscribe(x = Trace.WriteLine(“Result ” + x + ” on thread ” + Environment.CurrentManagedThreadId));

}

运行这段代码的话,就会发现计算过程是在线程池线程中进行的,计算结果在 UI 线程中

显示。另外,还会发现计算和结果会滞后于输入,形成等待的队列,这种现象出现的原因 在于,比起 100 秒 1 次的计算,鼠标移动的更新频率更高。Rx 中有几种技术可以处理这 种情况,其中一个常用方法是对输入流速进行限制,具体会在 5.4 节介绍。

讨论

实际上,ObserveOn 是把通知转移到一个 Rx 调度器上了。本节介绍了默认调度器(即线程 池)和一种创建 UI 调度器的方法。ObserveOn 最常用的功能是移到或移出 UI 线程,但调 度器也能用于别的场合。6.6 节介绍高级测试时,将再次关注调度器。

转载自 并发编程网 - ifeve.com
java线程的三种创建方式详细分析(全) 目录前言1. 继承Thread类2. 实现Runnable 接口3. 通过Callable和Future创建线程4. 总结 关于线程这部分内容讲的比较多,可看我之前的文章 【操作系统】线程与进程的深入剖析(全) 【操作系统】守护线程和守护进程的区别 对于线程Thread的分析 也可看我之前的文章 java之Thread类详细分析(全) java之Thread类实战模板(全) 多线程中run()和start()的异同详细分析(全) 对于创建方式的汇总以及方式 可看我这篇文章的总结对比 1. 继承
ServiceWorker工作原理、生命周期和使用场景 service worker 是现代web开发的关键部分,在最近几年获得了关注,这都要归功于 PWA(渐进式 Web 应用程序) 的流行。service worker 通过向典型的 Web 应用程序添加后台同步、离线渲染和推送通知等功能,缩小了本机应用程序和 Web 应用程序之间的差距,主要任务之一是充当代理。
Juc05_线程池概述、创建方式、七大参数、底层工作原理、拒绝策略(二) ③. 线程池的底层工作原理? ④. 线程池用过吗?生产上你是如何设置合理参数 ①. 线程池的拒绝策略请你谈谈 ②. 你在工作中单一的/固定数的/可变你的三种创建线程池的方法,你用哪个多?超级大坑
Java并发编程系列之四:自定义线程池拒绝策略 ThreadPoolExcutor是JDK自带的线程池,也是我们在创建线程池时经常用到的创建方法。对线程池稍微有了解的同学都知道,线程池是一种典型的池化缓存设计。JDK自带了四种任务拒绝策略,但是有时候是不能满足我们实际的业务需求的,所以此时我们需要自定义拒绝策略,来处理被线程池拒绝的任务。 自带线程池拒绝策略介绍 如何自定义拒绝策略