【问题标题】:Reactive Extensions subscribing to an observable (subject)订阅可观察对象(主题)的响应式扩展
【发布时间】:2015-08-19 14:10:53
【问题描述】:

我只是第一次在 winforms 应用程序中使用 Reactive Extensions。请注意,过去 4 年我一直在做 Web 开发,并且我非常熟悉淘汰赛中的可观察对象和可观察模式,我猜这会导致我在这里感到困惑。

无论如何,对于问题和代码。我正在构建一个简单的 winforms 实验(见下文)来说明我的问题。直到 start new 中的线程完成后,下面的订阅才会运行。我可以跟踪对 OnNext 的调用,但订阅直到有时 20-30 秒后才会触发。有人可以向我解释这种行为吗?

public partial class Form1 : Form
{

    private Subject<int> progress;
    private CancellationToken cancellationToken;
    private IScheduler _scheduler;

    public Form1()
    {
        InitializeComponent();

        CancellationTokenSource source = new CancellationTokenSource();
        cancellationToken = source.Token;

        _scheduler = new SynchronizationContextScheduler(SynchronizationContext.Current);


    }

    private void Start_Click(object sender, EventArgs e)
    {
        progress
            .ObserveOn(_scheduler)
            //.Throttle(TimeSpan.FromSeconds(5))
            .Subscribe(
                (i) => {
                    progressBar1.Do<ProgressBar>(ctl =>
                    {
                        ctl.Value = i;
                    });
                },
                (ex) => { },
            cancellationToken
        );

        Task counterTask = Task.Factory.StartNew(() =>
        {
            for (var i = 1; i < 101; i++)
            {
                Thread.Sleep(500);
                progress.OnNext(i);
            }
        }, cancellationToken,
        TaskCreationOptions.LongRunning,
        TaskScheduler.FromCurrentSynchronizationContext()
      );
    }

    private void Form1_Load(object sender, EventArgs e)
    {
       progress = new Subject<int>();
    }


}



public static class ControlExtensions
{
    public static void Do<TControl>(this TControl control, Action<TControl> action)
      where TControl : Control
    {
        if (control.InvokeRequired)
            control.Invoke(action, control);
        else
            action(control);
    }
}

【问题讨论】:

    标签: task-parallel-library system.reactive


    【解决方案1】:

    您的问题来自您的任务在 UI 线程上运行的事实,因为您使用的是TaskScheduler.FromCurrentSynchronizationContext()

    因此,您的各种 Sleep 调用阻塞了 UI 线程,冻结了 UI(例如,无法拖动窗口)并阻止您的可观察订阅执行(因为 ObserveOn,它应该在 UI 线程上执行调度程序)。

    TaskScheduler.FromCurrentSynchronizationContext() 替换为TaskScheduler.Default(后台TaskPool 线程),一切都会如您所愿。

    请注意,您无需调用Do/Invoke,因为您已经在您提供的调度程序的 UI 线程上。

    【讨论】:

    • 这是我有点迷路的地方。如果我将 StartNew 调度程序更改为 TaskScheduler.Default,就会发生一些奇怪的事情。如果我在 OnNext 处设置断点并运行它会冻结 IDE,我会等待光标等待几秒钟,然后按 F11,从那时起它就不会做任何事情。
    • 也许清理/重建/重新启动 VS ?我做了同样的场景,IDE很好。也尝试不带调试/断点,你应该得到你的行为。
    猜你喜欢
    • 1970-01-01
    • 2020-07-21
    • 2018-06-23
    • 1970-01-01
    • 1970-01-01
    • 2022-01-23
    • 2020-06-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多