Почему приведение объявления значения вместо аргумента функции приводит к другому поведению?

Почему приведение объявления значения вместо аргумента функции приводит к другому поведению?

Следующая операция зависает:

let duration = uint32 500
...
brick.DirectCommand.TurnMotorAtPowerForTimeAsync(motors, power, duration, breakEnabled) |> ignore

Следующая операция выполнена успешно:

brick.DirectCommand.TurnMotorAtPowerForTimeAsync(motors, power, uint32 500, breakEnabled) |> ignore

Какая разница?

Код:

let volume = 100
let frequency = uint16 1000
let duration = uint32 500
let power = 100
let motors = OutputPort.B ||| OutputPort.C
let breakEnabled = false

let moveAsync = async {

    let brick = Brick(UsbCommunication())

    brick.ConnectAsync() |> ignore
    brick.DirectCommand.TurnMotorAtPowerForTimeAsync(motors, power, duration, breakEnabled) |> ignore

    }

Async.RunSynchronously moveAsync

person Scott Nimrod    schedule 21.02.2016    source источник
comment
Я знаю, что это новый день, когда ты задаешь новый вопрос. Вы собираетесь получить значок с одним положительным вопросом в день в течение x дней?   -  person Guy Coder    schedule 21.02.2016
comment
@ Гай Кодер - Нет. Некоторые люди голосуют против моих вопросов. Я просто очень хочу повысить свою ценность. Чем больше я узнаю, чем больше я практикуюсь, чем больше я демонстрирую, тем больше я стою...   -  person Scott Nimrod    schedule 21.02.2016


Ответы (1)


То, что вы делаете, довольно странно, вам следует прочитать, как использовать async рабочий процесс. Тем не менее, то, что я ожидаю - при условии, что ваши функции действительно возвращают Async<'a> - примерно так:

let moveAsync = 
    async {
        let brick = Brick(UsbCommunication())

        do! brick.ConnectAsync() |> Async.Ignore
        let! _ = brick.DirectCommand.TurnMotorAtPowerForTimeAsync(motors, power, duration, breakEnabled)
    }

Вы хотите использовать let! или do! для составления асинхронных рабочих процессов — если у вас есть Async<'a> и вас не волнует возвращаемое значение, вы также можете использовать Async.Ignore, чтобы превратить его в Async<unit> (а не просто ignore).

Редактировать: Чтобы пояснить, почему я дал этот ответ, я даже не могу представить сценарий, в котором вы столкнетесь с проблемой, как указано.

Но у кода, который вы разместили, явно есть проблемы, которые, по моему мнению, не позволяют по-настоящему рассуждать о том, что происходит. Например, возвращать Tasks (которые могли быть запущены или нет) внутри асинхронного рабочего процесса, не дожидаясь их завершения. Если то, что делает этот код, соответствует вашим ожиданиям, я чувствую, что это только совпадение.

Моя интуиция подсказывает, что как только вы разберетесь с этими проблемами, вы увидите, что любой способ, которым вы передаете аргумент продолжительности, подходит.

person scrwtp    schedule 21.02.2016
comment
Спасибо @scrwtp. Однако я получаю следующую ошибку сборки: «Задача» несовместима с «Async‹’a›» - person Scott Nimrod; 21.02.2016
comment
Что ж, в таком случае эти функции возвращают .NET Tasks, а не F# Asyncs, и вы не можете их компоновать напрямую. - person scrwtp; 21.02.2016
comment
Проверьте этот поток, как с этим справиться: stackoverflow.com/questions/8022909/ - person scrwtp; 21.02.2016
comment
@ scrwtp - Спасибо за рекомендации по рекомендуемым практикам. Я обновил свой код, чтобы отразить ваше руководство. Однако я до сих пор не знаю ответа по теме вопроса. Я могу опубликовать отдельный вопрос для вас, чтобы опубликовать приведенный выше ответ, чтобы отдать вам должное, если хотите. - person Scott Nimrod; 21.02.2016
comment
Теперь это явно будет ставить телегу впереди лошади. Кроме того, проверьте редактирование. - person scrwtp; 21.02.2016