2016-06-02 8 views
2

Возможно, у меня есть 2 вопроса вместо одного, но в любом случае.Совместное отмена в F # с отменой продолжения

Я осуществляю совместное аннулирование как here suggested. Вот мой тестовый код:

type Async with 
    static member Isolate(f : CancellationToken -> Async<'T>) : Async<'T> = 
     async { 
      let! ct = Async.CancellationToken 
      let isolatedTask = Async.StartAsTask(f ct) 
      return! Async.AwaitTask isolatedTask 
     } 

let testLoop (ct: CancellationToken) = async { 
    let rec next ix = 
     if ct.IsCancellationRequested then() 
     else 
      printf "%i.." ix 
      Thread.Sleep 10 
      next (ix+1) 
    next 1 
} 

let cancellationSource = new CancellationTokenSource() 
let onDone() = printfn "!! DONE" 
let onError _ = printfn "!! ERROR" 
let onCancel _ = printfn "!! CANCEL" 

Async.StartWithContinuations (Async.Isolate testLoop, onDone, onError, onCancel, cancellationSource.Token) 

Thread.Sleep(100) 
cancellationSource.Cancel() 
Thread.Sleep(500) 

Как вы можете видеть, я начинаю асинхр с сделано, отменить и ошибки продолжений. Если я запустил этот код как есть, я получу следующий результат:

1..2..3..4..5..6..7..8 .. !! Совершено

Если я немного обновить метод Isolate следующим образом:

static member Isolate(f : CancellationToken -> Async<'T>) : Async<'T> = 
     async { 
      let! ct = Async.CancellationToken 
      let isolatedTask = Async.StartAsTask(f ct) 
      let! x = Async.AwaitTask isolatedTask 
      x 
     } 

я получить ожидаемый (сам) выход:

1..2..3..4 ..5..6..7 .. !! CANCEL

Почему у нас такая разница в поведении?

Возможно ли прервать testLoop, если оно не отменено в течение некоторого таймаута?

ответ

3

Блок async проверяет отмену Async.CancellationToken только до и после привязки (с использованием let!). Это означает, что когда токен отменяется, рабочий процесс будет отменен только тогда, когда будет сделано больше работы.

Следует также отметить, что в этом примере сам по себе не отменяется isolatedTask, поскольку он просто заканчивается регулярно (с использованием if).

В вашем случае:

  • При использовании только return!, задача возвращается регулярно, Async.AwaitTask возвращается регулярно, и ничего не будет сделано после этого, так что рабочий процесс завершается.

  • При использовании let! с последующим return, задача регулярно и Async.AwaitTask возвращается регулярно возвращается, но затем let! проверки для отмены до работает return и это отменяет рабочий процесс.