К сожалению, встроенная операция для этого не предоставляется Async
, но я все равно буду использовать асинхронные F #, потому что они напрямую поддерживают отмену.Когда вы запускаете рабочий процесс, используя Async.Start
, вы можете передать ему токен отмены, и рабочий процесс автоматически остановится, если токен будет отменен.
Это означает, что вы должны запускать рабочие процессы явно (вместо использования * 1005).*), поэтому синхронизация должна быть написана от руки.Вот простая версия метода Async.Choice
, который делает это (на данный момент он не обрабатывает исключения):
open System.Threading
type Microsoft.FSharp.Control.Async with
/// Takes several asynchronous workflows and returns
/// the result of the first workflow that successfuly completes
static member Choice(workflows) =
Async.FromContinuations(fun (cont, _, _) ->
let cts = new CancellationTokenSource()
let completed = ref false
let lockObj = new obj()
let synchronized f = lock lockObj f
/// Called when a result is available - the function uses locks
/// to make sure that it calls the continuation only once
let completeOnce res =
let run =
synchronized(fun () ->
if completed.Value then false
else completed := true; true)
if run then cont res
/// Workflow that will be started for each argument - run the
/// operation, cancel pending workflows and then return result
let runWorkflow workflow = async {
let! res = workflow
cts.Cancel()
completeOnce res }
// Start all workflows using cancellation token
for work in workflows do
Async.Start(runWorkflow work, cts.Token) )
Как только мы напишем эту операцию (которая немного сложна, но должнанаписать только один раз), решение проблемы довольно просто.Вы можете записать свои операции в виде асинхронных рабочих процессов, и они будут отменены автоматически после завершения первого:
let delayReturn n s = async {
do! Async.Sleep(n)
printfn "returning %s" s
return s }
Async.Choice [ delayReturn 1000 "First!"; delayReturn 5000 "Second!" ]
|> Async.RunSynchronously
Когда вы запустите это, он напечатает только «возвращение первым!»потому что второй рабочий процесс будет отменен.