Пример может быть более понятным, потому что он не демонстрирует никакого реального сценария.
Однако есть веская причина для переключения на другой поток до return
. Причина в том, что рабочий процесс, который вызывает вашу функцию (например, asyncMethod
), будет продолжать работать в контексте / потоке, на который вы переключаетесь перед возвратом. Например, если вы напишите:
Async.Start (async {
// Starts running on some thread (depends on how it is started - 'Async.Start' uses
// thread pool and 'Async.StartImmediate' uses the current thread
do! asyncMethod (fun () ->
Thread.Sleep(1000) ) // Blocks a newly created thread for 1 sec
// Continues running on the thread pool thread
Thread.Sleep(1000) }) // Blocks thread pool thread
Я думаю, что шаблон, использованный в примере, не совсем верен - асинхронные рабочие процессы всегда должны возвращаться к SynchronizationContext
, на котором они были запущены (например, если рабочий процесс запущен в потоке графического интерфейса, он может переключиться на новый поток, но затем должен вернуться обратно в поток GUI). Если бы я писал asyncMethod
функцию, я бы использовал:
let asyncMethod f = async {
let original = System.Threading.SynchronizationContext.Current
do! Async.SwitchToNewThread()
let result = f()
do! Async.SwitchToContext(original)
return result }
Чтобы ответить на ваш второй вопрос - причина, по которой операции SwitchTo
возвращают Async<unit>
и должны вызываться с использованием do!
, заключается в том, что нет способа напрямую переключиться на другой поток. Единственные точки, где вы получаете остальную часть рабочего процесса как функцию (которую вы можете выполнить в новом потоке), это когда вы используете do!
или let!
Тип Async<T>
, по сути, это просто некоторый объект, который получает функцию ( остальная часть рабочего процесса) и может выполнить его где угодно, но другого способа «нарушить» рабочий процесс не существует.