F #: назначение SwitchToThreadPool непосредственно перед асинхронным возвратом - PullRequest
8 голосов
/ 25 марта 2011

В документах MS для Async.SwitchToNewThread один из приведенных примеров:

let asyncMethod f = 
    async {  
        do! Async.SwitchToNewThread() 
        let result = f() 
        do! Async.SwitchToThreadPool() 
        return result
    } 

Какова цель переключения на пул потоков непосредственно перед оператором возврата? Я понимаю, почему вы можете захотеть переключиться с выделенного потока на пул потоков, когда асинхронному блоку нужно проделать большую работу, но здесь это не так.

Это не является частью основного вопроса, но мне также любопытно узнать, почему SwitchToNewThread и SwitchToThreadPool возвращают Async. Есть ли когда-нибудь случай использования, при котором вы бы не хотели сразу «делать!» эти задачи? Спасибо

1 Ответ

11 голосов
/ 25 марта 2011

Пример может быть более понятным, потому что он не демонстрирует никакого реального сценария.

Однако есть веская причина для переключения на другой поток до 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>, по сути, это просто некоторый объект, который получает функцию ( остальная часть рабочего процесса) и может выполнить его где угодно, но другого способа «нарушить» рабочий процесс не существует.

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