为什么 dispose 在 Scheduler.Default.Schedule() 中什么都不做?

Why dispose does nothing in Scheduler.Default.Schedule()?

我们正在为 .Net 使用 ReactiveExtensions

我们像这样在线程池上将代码安排到 运行:

IDisposable myDisposable = Scheduler.Default.Schedule(() =>
{
    int count = 0;
    while (true)
    {
        Console.WriteLine(++count);
        Thread.Sleep(500);
    }
});

Console.ReadKey();

myDisposable.Dispose(); // WHY THIS DO NOTHING?!?!

Console.ReadKey();

如您所见,这是 运行 在控制台应用程序上的测试代码。

当我配置预定代码时,代码保持运行ning!

我没有可以检查的标志,我无法添加 if 语句来自行停止预定代码。

谁能解释一下?如果它不起作用,为什么我会得到一个 IDisposable?以及为什么我没有得到某种标志(CancellationToken??)来检查我的代码,以便我可以及时终止它的 运行ning?

谢谢!

您的代码继续运行的原因是您期望 Dispose() 调用神奇地退出硬循环(while(true) 部分)。

您可以设置一个变量 - 并在您的 dispose 方法中取消设置该变量,例如:

_isRunning = true;
while(_isRunning)
{
    // do stuff
}

然后在你的dispose方法中,调用:

_isRunning = false;

我在这里的回答中发布了一种实现 .Net 任务调度的方法,这可能会有所帮助: Best way to create a "run-once" time delayed function in C#

您面临的问题是,一旦您的线程进入 while (true) 循环,它就会被困住并且永远无法结束。 .Dispose() 没有什么神奇的东西可以停止线程。

事实上,在您调用 .Dispose() 之前,一次性用品已经处理完毕。由于您使用了 .Schedule 的重载,它只会在代码启动后立即处理订阅后运行。

您需要做的是使用支持重新安排的重载。幸运的是那里已经有一个了。试试这个代码:

IDisposable myDisposable = Scheduler.Default.Schedule(0, TimeSpan.Zero, (count, reschedule) =>
{
    Console.WriteLine(count);
    reschedule(count + 1, TimeSpan.FromSeconds(0.5));
});

这完全符合您的要求 - 它可以正确处理。

话虽如此,您正在使用 Rx,所以您不妨只使用标准的可观察运算符。这也有效:

IDisposable myDisposable =
    Observable
        .Timer(TimeSpan.Zero, TimeSpan.FromSeconds(0.5))
        .Subscribe(count => Console.WriteLine(count));

简单。