Важно отметить, что асинхронное программирование - это выполнение операций, которые не связаны с процессором, то есть те, которые связаны с вводом-выводом.Эти операции ввода-вывода выполняются в потоках ввода-вывода (с использованием функции перекрывающегося ввода-вывода операционной системы).Это означает, что даже если вы оберните некоторую факториальную функцию внутри асинхронного блока и запустите ее внутри другого асинхронного блока, используя привязку let!
, вы не получите никакой выгоды от этого, так как она будет работать в потоке, связанном с ЦП, иОсновная цель асинхронного программирования - не брать поток, связанный с процессором, когда что-то имеет характер ввода-вывода, поскольку этот поток, связанный с процессором, может использоваться для других целей в то время, когда завершается ввод-вывод.
Если вы посмотрите на различные классы ввода-вывода в .NET, такие как File, Socket и т. Д. Все они имеют блокирующие, а также неблокирующие операции чтения и записи.Операции блокирования будут ожидать завершения ввода-вывода в потоке ЦП и, следовательно, блокирования потока ЦП до завершения ввода-вывода, при этом в качестве неблокирующих операций используются перекрывающиеся вызовы API-интерфейса ввода-вывода для выполнения операции.
У Async есть метод, позволяющий сделать асинхронный блок из этих неблокирующих API-интерфейсов файлов, сокетов и т. Д. В вашем случае вызов DownloadString заблокирует поток ЦП, поскольку он использует API-интерфейс блокировки базового класса, где как AsyncDownloadString
использует API-интерфейс без блокировки - io с перекрытием.