Почему функция C# Rx Subscribe () не работает с ключевым словом asyn c? - PullRequest
1 голос
/ 07 марта 2020

У меня есть фрагмент кода:

static void Main(string[] args)
{
    Observable.Range(1, 5).Subscribe(async x => await DoTheThing(x));
    Console.WriteLine("done");
}

static async Task DoTheThing(int x)
{
    await Task.Delay(TimeSpan.FromSeconds(x));
    Console.WriteLine(x);
}

Я надеюсь, что это будет l oop 5 раз, и после каждого l oop будет строка, напечатанная как

1
2
3
4
5

Но, что удивительно, это напечатает «выполнено» и сразу прекратит работу. Кажется, что async + await не дождался Task.Delay и завершил работу.

В семантике, похоже, нет проблем, поэтому где я ошибся насчет Subscribe или asyn c, как это исправить? выполнить мой запрос вызова асинхронных задач из Rx?

Спасибо.

1 Ответ

5 голосов
/ 07 марта 2020

Это не блокировка, потому что это хорошо - асинхронно. Ваш код генерирует пять задач, все они выполняются параллельно, все выполняются в разное время.

Но они не блокируют функцию Main. Если вы просто добавите Console.ReadKey() в качестве последней строки, вы увидите, что ваш код работает в фоновом режиме. Он печатает.

static void Main(string[] args)
{
    Observable.Range(1, 5).Subscribe(async x => await DoTheThing(x));
    Console.WriteLine("done");
    Console.ReadKey();
}

Но предположим, что вы хотите подождать, пока все они не будут выполнены. Что тогда?

Конечно, есть .Wait(), но это блокировка. Давайте рассмотрим все наши задачи как наблюдаемые.

Мы будем использовать C# 7 async Main, пока мы на нем.

static async Task Main(string[] args)
{
    await Observable.Range(1, 5)
        .Select(x => DoTheThing(x).ToObservable())
        .Merge();                

    Console.WriteLine("done");
}

Это работает точно так, как вы ожидаете это к.

...