Как использовать FSharpx TaskBuilder с функциями, принимающими параметры

Недавно я программировал с помощью библиотеки FSharpx и особенно ее TaskBuilder. Теперь мне интересно, можно ли определить функцию, которая принимает параметры и получает результат. Такие как

 let doTask(parameter:int) =
     let task = TaskBuilder(scheduler = TaskScheduler.Current)        
     task {
         return! Task.Factory.StartNew(fun() -> parameter + 1)
     } 

 match FSharpx.Task.run doTask(1) with
 | _ -> ()

Глядя на исходный код, я вижу run ожидает, что функция не принимает параметров и возвращает Task<'a>. Не похоже, чтобы были примеры на FSharpx TaskTests либо.

Я был бы признателен, если бы кто-нибудь мог посоветовать, как мне реализовать такой сценарий с FSharpx, или если кто-то не должен использовать такую ​​​​библиотеку по причине, которую я еще не совсем понял.

‹изменить: я думаю, что могу обернуть doTask следующим образом

 wrapperDoTask() = doTask(101)
 match FSharpx.Task.run wrapperDoTask with
 | _ -> ()

И это может сработать. В настоящее время я не работаю с компилятором, так что это немного махание руками. У кого-нибудь есть мнение по какому-либо направлению или я просто ответил на свой вопрос? :)

‹edit2: я думаю, что мне нужно отредактировать это еще раз на основе ответа MisterMetaphor. Особенно его P.S., я думаю, был хорошо информирован. Я использую FSharpx TaskBuilder для взаимодействия с C#, в котором, как уже отмечалось, задачи возвращаются как горячие (за некоторыми незначительными исключениями), уже запущенные. Это связано с моим недавним вопросом Преобразование кода C# с асинхронным ожиданием в F# относительно планировщика и относительно Orleans ( Я добавлю несколько тегов, чтобы усилить контекст, может быть, кто-то еще размышляет над этим).

Говоря с точки зрения C#, я пытаюсь добиться ожидания результата задачи перед возвратом, но без блокировки. Поведение, которое мне нужно, особенно относится к поведению await, а не .Result. Разницу можно прочитать, например, из

Пытаться понять, какой контекст, или планировщик, или поведение, или что-то еще происходит с точки зрения C#, для меня несколько нечетко. К сожалению, похоже, что я не могу игнорировать все детали, когда дело доходит до взаимодействия. :)


person Veksi    schedule 27.07.2014    source источник


Ответы (1)


Вам нужно использовать Task.run только в том случае, если вы хотите дождаться завершения задачи синхронно в текущем потоке. Он принимает один параметр, и вы можете рассматривать этот параметр как фабрику задач, то есть средство для создания Task<_>. В отличие от Async<_>, Task<_> запускается сразу после создания. Это не всегда желательное поведение.

Вы могли бы добиться аналогичных результатов (блокировка ожидания завершения задачи) с (doTask 101).Result, но я думаю, что Task.run более идиоматичен для F#, так как он использует возвращаемый тип Result для сигнализации об ошибке, а не для возбуждения исключения. Можно спорить, что лучше, в зависимости от ситуации, но по моему опыту в более простых случаях специальный тип результата более компонуем, чем исключения.

Еще один момент заключается в том, что вам следует избегать блокировки ожиданий (Task.run, .Wait(), .Result) настолько, насколько это возможно. (В идеале у вас должен быть один из них только на верхнем уровне вашей программы.)

P.S. Это, если выходит за рамки вопроса, но ваша функция doTask выглядит забавно. task { return! Task.Factory.StartNew( ... ) } эквивалентно Task.Factory.StartNew( ... ). То, что вы, вероятно, хотели сделать, это task { return parameter + 1 }.

РЕДАКТИРОВАТЬ

Итак, в ответ на редактирование вопроса OP :) Если вам нужно поведение await из С#, вам просто нужно использовать let! .... Как это:

task {
    let! x = someTask 1 2 3
    return x + 5
}
person MisterMetaphor    schedule 27.07.2014
comment
Я не уверен, что мне следует уточнить это по моему вопросу, но я использую эту библиотеку для взаимодействия с библиотеками C #, и я подозреваю, что другие новички в F # имеют аналогичные проблемы. Ваш P.S. уже дал мне несколько a-has! Когда дело доходит до многопоточности, я хорошо знаком с async-await (не эксперт, деталей, кажется, всегда предостаточно), а что касается F#, то я обычно использовал Async, как предполагалось. Этот вопрос проистекает из страны С#, где некоторая функция возвращает горячую задачу/задачу, как вы заметили. Я использую TaskBuilder для взаимодействия и сбора результатов. Действительно, прежде чем вернуться, я хотел бы сделать ожидание - person Veksi; 27.07.2014
comment
Если вам не нужна сложная конфигурация TaskFactory, для взаимодействия с C# вы, вероятно, можете обойтись только Async.AwaitTask и Async.StartAsTask. В этом случае вы можете использовать обычный async в коде F#. - person MisterMetaphor; 27.07.2014
comment
P.S. ОК, я только что заметил ваш другой вопрос, и я думаю, вам следует придерживаться FSharpx TaskBuilder :) - person MisterMetaphor; 27.07.2014
comment
Хех, действительно. Я только что отредактировал свой вопрос. Может быть, я должен был сделать это наоборот. :) В любом случае, это await вызывает у меня некоторую головную боль, поскольку это поведение, которое я хотел бы иметь, и поиск механических паттернов, чтобы мне не нужно было обдумывать столько деталей в моя голова. Кстати, мне нужно подумать, есть ли что-то еще в этой истории. Если я ничего не придумаю (или кого-то еще), я соглашусь с этим. Это П.С. был хорошим, спасибо, что нашли время подумать и написать его. - person Veksi; 27.07.2014
comment
Рад, что смог помочь. Я отредактировал ответ и добавил ответ о await. - person MisterMetaphor; 27.07.2014