F # await Task и использование его результата - PullRequest
0 голосов
/ 16 июня 2020

Я немного новичок в F #, я пытаюсь использовать классы C# внутри модуля F #.

let getApps (context: MyContext) =
    context.Provider.GetService<AppRepository>().GetActiveAsync().Result
    |> List.ofSeq
    |> List.map printName
    |> ignore

C# разработчик во мне кричит: .Result это плохо ? . Итак, мой вопрос в том, как преобразовать этот код в более элегантный способ, а также воспользоваться преимуществами правильного программирования asyn c на F #.

Я пытался использовать разные варианты:

|> Async.AwaitTask
|> Async.RunSynchronously

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

Ответы [ 2 ]

4 голосов
/ 17 июня 2020

Следует иметь в виду, что Async.RunSynchronously по сути то же самое, что доступ к Result. Обе эти операции блокируют текущий поток, ждут завершения фоновой операции и затем дают вам результат.

Это означает, что нет смысла использовать async { .. }, если вам нужно будет дождаться результата, используя RunSynchronously. (Помимо того факта, что RunSynchronously имеет очень длинное и уродливое имя, которое явно и ясно говорит вам, что это то, что происходит!)

Если вы можете структурировать свой код так, чтобы вам не нужно было ждать , то стоит изменить getApps, чтобы он возвращал результат асинхронно:

let getApps (context: MyContext) = async {        
  let! repos = 
    context.Provider.GetService<AppRepository>().GetActiveAsync()
    |> Async.AwaitTask
  return repos |> List.map printName }

Затем вы можете вызвать это из другого блока async { .. } и, в конечном итоге, запустить вычисление в фоновом режиме с помощью Async.Start. Однако нет смысла делать это, если вы будете использовать Async.RunSynchronously.

1 голос
/ 17 июня 2020

Следующее должно помочь:

let getApps (context: MyContext) =
    async{
       let! result = context.Provider.GetService<AppRepository>().GetActiveAsync() 
                     |> Async.AwaitTask

       result
       |> Seq.iter printName
    }

getApps ctx
|> Async.RunSynchronously

Таким образом, вы не блокируете поток, ожидая, пока GetActive завершит sh. Кстати, если вы что-то выполняете, вы можете использовать Seq.iter вместо Seq.map, и вам не нужно преобразовывать его в список. Вы можете работать с последовательностью

...