Вызов метода в заданном интервале c - PullRequest
1 голос
/ 24 февраля 2020

Мне нужно запустить метод с заданным интервалом c. Как я могу достичь этого через c#

Я написал код, но он не повторяется. Это выполняется только один раз. Может кто-нибудь объяснить мне, что является наблюдаемым и аннулирование токена. как это использовать

IObservable<long> observable = Observable.Interval(TimeSpan.FromHours(1));
System.Threading.CancellationTokenSource source = new System.Threading.CancellationTokenSource();
observable.Subscribe(x =>
{
    System.Threading.Tasks.Task task = sampleMethod();
    task.Start();
}, source.Token);

Ответы [ 4 ]

2 голосов
/ 24 февраля 2020

Вы можете достичь этого несколькими способами. Одним из самых простых будет что-то вроде этого:

public async Task RunScheduleJob(CancellationToken token)
{
  while(!token.IsCancellationRequest)
  {
    YourMethod();
    await Task.Delay(TimeSpan.FromHours(1), token)
  }
}

PS. Для такой простой работы вам не нужно использовать Reactive Extensions или любую другую внешнюю библиотеку. Вы можете достичь этого, просто играя с Task экземплярами

1 голос
/ 27 февраля 2020

Rx - отличный способ справиться с этой ситуацией. Он очень чистый.

Самая основная c перезапись вашего кода в вашем вопросе такова:

IObservable<Unit> observable =
    from i in Observable.Interval(TimeSpan.FromHours(1))
    from t in Observable.FromAsync(() => sampleMethod())
    select t;

IDisposable subscription = observable.Subscribe();

Нет необходимости в токене отмены, так как вам просто нужно позвонить subscription.Dispose() чтобы остановить эту подписку.

Однако, если ваш sampleMethod() вызов был длительным, то вызов subscription.Dispose() остановит наблюдаемое, но задача будет выполнена до конца. Если вы специально хотели остановить задачу, то для вызова этой задачи потребуется взять токен отмены и использовать его для остановки самого себя.

Ваш код вызова будет таким:

IObservable<Unit> observable =
    from i in Observable.Interval(TimeSpan.FromHours(1))
    from t in Observable.FromAsync(ct => sampleMethod(ct))
    select t;

Единственное отличие состоит в том, что вызов FromAsync передает CancellationToken вызову sampleMethod, который будет отменен при вызове subscription.Dispose().

0 голосов
/ 24 февраля 2020

Нет необходимости в Rx, если вам просто нужна функциональность таймера. Вы можете просто go с Timer из System.Threading:

    var timer = new Timer(_ =>
    {
        // repeating code goes here
        // the argument is an optional state that you can pass into the constructor
    });
    timer.Change( dueTime: TimeSpan.FromSeconds(1), period: TimeSpan.FromSeconds(0.1));
    // run your app
    timer.Dispose();

Преимущество таймера в том, что он позволяет вам перенастроить его в любое время (если вы хотите изменить период, просто позвоните Change снова), временно отключите его и удалите его (вызывая Dispose).

0 голосов
/ 24 февраля 2020

Observable.Interval(TimeSpan.FromHours(1)).SelectMany(_ => sampleMethod()).Subscribe(). Игнорируя поведение отмены момента (которое легко добавить), вы просто берете Interval и правильно сопоставляете его с асинхронной c подпрограммой, представленной как Task (внутренне рассматривается как IObservable<>, кстати, есть .ToObservable() метод расширения для преобразования Task). Обратите внимание, что SelectMany(...) здесь судьбоносно важен: в противном случае инфраструктура Rx не будет ожидать завершения Task, не будет фиксировать возможные исключения и не сохранит исходный порядок событий.

CancellationToken используется для отмены подписки на Observable, которую вы составили. Это аналогично IDisposable в том смысле, что оба служат одной и той же цели: остановить и очистить вашу подписку. Таким образом, как только вы позвоните по номеру Cancel(), вы не получите никаких обновлений.

PS Вы уверены, что FromHours(1) правильно? Возможно, вы захотите менее длительный интервал, например FromMinutre(1).

...