Использование встроенной в F # асинхронной поддержки с методами * Async () - PullRequest
1 голос
/ 12 октября 2009

Как использовать встроенную поддержку F # для классов асинхронных операций, раскрывающих Асинхронный шаблон на основе событий , такой как WebClient класс?

let Download(url : Uri) =
    let client = new WebClient()
    let html = client.DownloadString(url)
    html

Когда я пытаюсь изменить это, чтобы использовать "let!" в асинхронном блоке (скажем, как описано в недавней публикации Сомы )

let Download(url : Uri) =
    async {
    let client = new WebClient()
    let! html = client.DownloadStringAsync(url)
    return html }

Я получаю сообщение об ошибке:

Несоответствие ограничения типа. Тип unit не совместим с типом Async <'a> Тип' unit 'несовместим с типом' Async <'a>'

Редактировать: я действительно спрашиваю об общем вопросе использования * Async () методов, WebClient - простой пример. Microsoft говорит"... вы должны предоставлять асинхронные функции, используя асинхронный шаблон на основе событий [в отличие от BeginFoo () / EndFoo ()], когда это возможно ...", поэтому я думаю, что должно быть простой способ использовать произвольный метод * Async () из F #.

1 Ответ

5 голосов
/ 12 октября 2009

Метод WebClient.DownloadStringAsync является частью платформы .NET. Он будет вызывать событие, чтобы сигнализировать о его прогрессе, и его тип возвращаемого значения будет unit, поэтому вы не хотите его использовать, и нет никакого преимущества в его оборачивании в async объект.

F # PowerPack определяет метод расширения, val webclient.AsyncDownloadString : uri -> Async{string}:

let Download(url : Uri) =
    async {
    let client = new WebClient()
    client.Encoding <- Encoding.GetEncoding("utf-8")
    let! html = client.AsyncDownloadString(url)
    return html }

К сожалению, выбор имени вступает в противоречие с существующим методом веб-клиента, что вполне может вызвать путаницу. Однако я считаю, что все асинхронные расширения F # начинаются с Async*.


[Изменить, чтобы добавить в ответ на комментарии:]

Обычно .NET использует шаблон BeginFoo / EndFoo для параллелизма. Если типы верны, вы можете просто использовать Async.BuildPrimitive beginMethod endMethod, который возвратит асинхронную оболочку для метода.

Иногда объекты не используют этот шаблон, например WebClient, и вам действительно нужно использовать Async.AwaitEvent, чтобы дождаться запуска события или написать свой собственный цикл, чтобы многократно проверять, установлен ли bool. Вот хорошая статья о преобразовании событий в асинхронные объекты .

Для чего стоит, если у вас установлен F #, у вас также должен быть исходный код, который даст вам представление о том, как команда F # реализует свои асинхронные расширения. На моей машине соответствующий файл находится по адресу:

C:\Program Files\FSharp-1.9.6.16\source\fsppack\FSharp.PowerPack\AsyncOperations.fs
...