Необходимость использования ObserveOn для Observables? - PullRequest
3 голосов
/ 31 января 2012

См. Следующий код:

 var obs = Observable.Start(() => LongRunningMethodToRetrieveData());

 obs.Subscribe(x => MethodThatMustBeOnUIThread(x));

Если я уверен, что эти 2 строки кода выполняются в потоке пользовательского интерфейса, необходимо ли сначала вызвать ObserveOn(SynchronizationContext.Current)?Или аналогично, мне нужно проверить InvokeRequired внутри MethodThatMustBeOnUIThread?

В принципе, гарантирую ли я с этими двумя строками кода, что OnNext будет вызываться в потоке, который создает подписку?

Спасибо.

РедактироватьНу, я попробовал в отладчике и «MethodThatMustBeOnUIThread» действительно вызывается из фонового потока.Почему это?Теперь я предполагаю, что наблюдение происходит по умолчанию в потоке, в котором запущен асинхронный метод.

1 Ответ

1 голос
/ 31 января 2012

Вам необходимо ознакомиться с планировщиком по умолчанию, используемым различными методами Rx.

Методы, подобные Observable.Generate, выполняются в потоке, который подписывается на наблюдаемое.

С другой стороныС другой стороны, цель метода Observable.Start состоит в том, чтобы асинхронно вызывать действие lamdba при подписке на наблюдаемое.Это не будет асинхронным, если это произойдет в потоке пользовательского интерфейса.Так что в этом случае он использует планировщик ThreadPool.

Это можно увидеть с помощью Reflector.NET:

public static IObservable<TSource> Start<TSource>(Func<TSource> function)
{
    if (function == null)
    {
        throw new ArgumentNullException("function");
    }
    return function.ToAsync<TSource>()();
}

public static Func<IObservable<TResult>> ToAsync<TResult>(
    this Func<TResult> function)
{
    if (function == null)
    {
        throw new ArgumentNullException("function");
    }
    return function.ToAsync<TResult>(Scheduler.ThreadPool);
}

Итак, зная используемый планировщик, вы должны использовать форму ObserveOn перед вызовом Subscribe, если вы хотите, чтобы подписка работала в потоке пользовательского интерфейса.

Кроме того, поскольку вы используете Rx, я бы не стал использовать InvokeRequired - это просто смешивание моделей асинхронного кодирования.Rx имеет все, что вам нужно, чтобы красиво играть с потоками.

...