反应式扩展、锁和线程

Posted

技术标签:

【中文标题】反应式扩展、锁和线程【英文标题】:Reactive Extensions, locks and threads 【发布时间】:2010-12-08 13:28:53 【问题描述】:

我正在使用响应式扩展来处理 wpf ui,基本上我有一个文本框,我需要在小时间跨度(200-300毫秒)

问题在于它有些不可预测,有时会立即触发油门,这可能是因为 TextUpdated 事件没有到达可观察对象或可观察对象本身。我也在做一些可能会干扰的锁定,但这通常是通过新任务完成的,而不是在 UI 线程上。我还偷偷怀疑调试可能会影响行为,因为当我设置断点时它似乎更“不正确”地触发了

由于 observable 是在 UI 线程上创建的,我假设(可能是错误的)它是计时器或它在下面使用的任何东西也在该线程上,创建一个新线程来创建 observable 可能是个好主意,这样它就不会受到干扰通过 UI 开销和潜在的锁定?我如何以最好的方式设置这样一个线程,我猜它末尾的空while循环可能不是一个好主意:)

Throttle、Sample 工作以及与线程相关的响应式扩展如何在后台工作?

编辑

似乎问题出在我测试它的方式上:P 如果你按住一个键,它开始重复之前似乎有 500 毫秒的延迟,如果你只是敲击键它工作正常。叹息

【问题讨论】:

您是否大量使用 ThreadPool(除了通过 Sample/Throttle 隐式使用)? 【参考方案1】:

SampleThrottle 都使用 Scheduler.ThreadPool 作为他们的时间,所以我很怀疑这是问题所在。

我建议在代码中添加一些日志记录以找出瓶颈所在:

sourceEvents.LogInterval("Source")
    .Throttle(throttleTimeSpan).LogInterval("Throttled")
    .Sample(sampleTimeSpan).LogInterval("Sample")
    .Subscribe();

这里是LogInterval的定义:

public static class ObservableEx

    public static IObservable<TSource> LogInterval(
        this IObservable<TSource> source, string message)
    
        return source
            .TimeInterval()
            .Do(x => Debug.WriteLine("0 :: 1 (2)", 
                message, x.Value, x.Interval.TotalMilliseconds);
            .RemoveTimeInteval();
    

如果瓶颈是节流阀/样本,则可能意味着您在其他地方使线程池饱和。如果是这种情况,并且这些节流阀的性能很重要,您可以考虑创建一个专用线程+调度程序并为 Throttle/Sample 使用自定义 DistpatcherScheduler。或者,可能有更好的 TPL 方法来解决它。

【讨论】:

问题是一个简化的版本,它只是一个 wpf 文本框和两个不同的响应式扩展连接到它的 textchanged observable 效果很好。当应用程序的负载增加时,问题似乎就开始了。可能是因为我也在使用并行扩展,我可能已经饱和了线程池或响应式扩展的东西? 查看更新以追踪瓶颈。是的,如果您大量使用 ThreadPool,则可能根本没有足够的可用资源。

以上是关于反应式扩展、锁和线程的主要内容,如果未能解决你的问题,请参考以下文章

Quartz 与“反应式扩展”

反应式扩展是不是支持滚动缓冲区?

反应式扩展是不是支持滚动缓冲区?

开源 | RSocket Broker:阿里巴巴开源的基于 RSocket 协议的反应式程控消息交换系统

打字稿扩展反应原生视图组件

谷歌浏览器安装没反应