Почему утилита ничего не делает в Scheduler.Default.Schedule ()? - PullRequest
0 голосов
/ 29 октября 2018

Мы работаем с ReactiveExtensions для .Net

Мы планируем запуск кода в пуле потоков следующим образом:

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();

Как видите, это тестовый код, который запускается в консольном приложении.

Когда я распоряжаюсь запланированным кодом, код продолжает работать!

У меня нет флага, который я могу проверить, я не могу добавить оператор if, чтобы самостоятельно остановить запланированный код.

Кто-то может объяснить это? Почему я могу получить IDisposable, если он не работает? и почему я не получаю какой-либо флаг (CancellationToken ??) для проверки внутри моего кода, чтобы я мог своевременно прекратить его выполнение?

Спасибо!

Ответы [ 2 ]

0 голосов
/ 30 октября 2018

Проблема, с которой вы сталкиваетесь, заключается в том, что как только ваш поток попадает в цикл 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));

Simple.

0 голосов
/ 29 октября 2018

Причина, по которой ваш код продолжается, заключается в том, что вы ожидаете, что вызов Dispose () волшебным образом выйдет из жесткого цикла (часть while (true)).

Вы можете установить переменную - и в вашем методе dispose удалить переменную, например ::

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

Затем в вашем методе dispose вызовите:

_isRunning = false;

В своем ответе я опубликовал способ достижения планирования задач .Net, который может помочь: Лучший способ создать «однократную» функцию с задержкой по времени в C #

...