«Асинхронность» в этом примере не связана с параллелизмом или экономией времени, скорее, речь идет о предоставлении хорошей модели программирования без блокировки (читай: тратить) потоков.
Если вы используете другие языки программирования, обычно у вас есть два варианта:
Вы можете заблокировать , обычно вызывая синхронные методы. Недостатком является то, что поток потребляется и не выполняет никакой полезной работы, пока он ожидает дискового или сетевого ввода-вывода или чего-то еще. Преимущество в том, что код простой (обычный код).
Вы можете использовать callbacks для асинхронного вызова и получения уведомлений о завершении операций. Преимущество состоит в том, что вы не блокируете потоки (эти потоки могут быть возвращены, например, в ThreadPool, и новый поток ThreadPool будет использоваться после завершения операции, чтобы перезвонить вам). Недостатком является то, что простой блок кода разделяется на набор методов обратного вызова или лямбда-выражений, и это быстро становится очень сложным для поддержки обработки состояния / потока управления / исключения через обратные вызовы.
Итак, вы находитесь между молотом и наковальней; Вы либо отказываетесь от простой модели программирования, либо тратите впустую потоки.
Модель F # дает лучшее из обоих миров; Вы не блокируете потоки, но сохраняете простую модель программирования. Такие конструкции, как let!
, позволяют вам выполнять 'thread-hop' в середине асинхронного блока, поэтому в коде, подобном
Blah1()
let! x = AsyncOp()
Blah2()
Blah1
может работать, скажем, в потоке # 13 ThreadPool, но затем AsyncOp освободит этот поток обратно в ThreadPool. Позже, когда AsyncOp завершит работу, остальная часть кода начнет резервное копирование в доступном потоке (может быть, скажем, в ThreadPool thread # 20), который связывает x
с результатом и затем запускает Blah2
. В простых клиентских приложениях это редко имеет значение (за исключением случаев, когда вы гарантируете, что не блокируете поток пользовательского интерфейса), но в серверных приложениях, которые выполняют ввод / вывод (где потоки часто являются ценным ресурсом - потоки дороги и вы не можете тратить их впустую блокирующий) неблокирующий ввод-вывод часто является единственным способом масштабирования приложения. F # позволяет вам писать неблокирующие операции ввода / вывода, не превращая программу в массу обратных вызовов спагетти-кода.
Смотри также
Рекомендации по распараллеливанию с использованием асинхронного рабочего процесса
Как сделать цепные обратные вызовы в F #?
http://cs.hubfs.net/forums/thread/8262.aspx