Лучшие практики для распараллеливания с использованием асинхронного рабочего процесса - PullRequest
8 голосов
/ 30 января 2009

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

let getAllHyperlinks(url:string) =
    async {  let req = WebRequest.Create(url)
             let! rsp = req.GetResponseAsync()
             use stream = rsp.GetResponseStream()             // depends on rsp
             use reader = new System.IO.StreamReader(stream)  // depends on stream
             let! data = reader.AsyncReadToEnd()              // depends on reader
             return extractAllUrls(data) }                    // depends on data

let! указывает F # выполнить код в другом потоке, затем связать результат с переменной и продолжить обработку. В приведенном выше примере используются два оператора let: один для получения ответа, а другой для чтения всех данных, поэтому он порождает как минимум два потока (пожалуйста, исправьте меня, если я ошибаюсь).

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

Есть ли польза от наличия более одного let! в приведенном выше коде?

Если нет, то как нужно изменить этот код, чтобы использовать несколько операторов let!?

Ответы [ 2 ]

9 голосов
/ 30 января 2009

Ключ в том, что мы не порождаем новые темы. В течение всего рабочего процесса из ThreadPool используется 1 или 0 активных потоков. (Исключение, вплоть до первого '!', Код выполняется в пользовательском потоке, который выполнил Async.Run.) "Let!" освобождает поток, когда асинхронная операция находится в море, а затем возвращает поток из ThreadPool, когда операция возвращается. Преимущество (производительности) - меньшее давление на ThreadPool (и, конечно, главное преимущество пользователя - простая модель программирования - в миллион раз лучше, чем все то, что вы пишете в BeginFoo / EndFoo / callback).

См. Также http://cs.hubfs.net/forums/thread/8262.aspx

3 голосов
/ 30 января 2009

Я писал ответ, но Брайан опередил меня. Я полностью согласен с ним.

Я хотел бы добавить, что если вы хотите распараллелить синхронный код, правильным инструментом будет PLINQ, а не асинхронные рабочие процессы, как объясняет Дон Сайм .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...