title: How to cancel individual async computation, being run in parallel with others, from a button click event
body: <p>I've prepared the following WinForms code to be as simple as possible to help answer my question. You can see I have a start button which sets up and runs 3 different async computations in parallel which each do some work and then update labels with a result. I have 3 cancel buttons corresponding to each async computation being run in parallel. How can I wire up these cancel buttons to cancel their corresponding async computations, while allowing the others to continue running in parallel? Thanks!</p>
  
  <pre><code>open System.Windows.Forms
  
  type MyForm() as this =
      inherit Form()
      let lbl1 = new Label(AutoSize=true, Text="Press Start")
      let lbl2 = new Label(AutoSize=true, Text="Press Start")
      let lbl3 = new Label(AutoSize=true, Text="Press Start")
  
      let cancelBtn1 = new Button(AutoSize=true,Enabled=false, Text="Cancel")
      let cancelBtn2 = new Button(AutoSize=true,Enabled=false, Text="Cancel")
      let cancelBtn3 = new Button(AutoSize=true,Enabled=false, Text="Cancel")
  
      let startBtn = new Button(AutoSize=true,Text="Start")
  
      let panel = new FlowLayoutPanel(AutoSize=true, Dock=DockStyle.Fill, FlowDirection=FlowDirection.TopDown)
      do
          panel.Controls.AddRange [|startBtn; lbl1; cancelBtn1; lbl2; cancelBtn2; lbl3; cancelBtn3; |]
          this.Controls.Add(panel)
  
          startBtn.Click.Add &lt;| fun _ -&gt;
              startBtn.Enabled &lt;- false
              [lbl1;lbl2;lbl3] |&gt; List.iter (fun lbl -&gt; lbl.Text &lt;- "Loading...")
              [cancelBtn1;cancelBtn2;cancelBtn3] |&gt; List.iter (fun cancelBtn -&gt; cancelBtn.Enabled &lt;- true)
  
              let guiContext = System.Threading.SynchronizationContext.Current
  
              let work (timeout:int) = //work is not aware it is being run within an async computation
                  System.Threading.Thread.Sleep(timeout)
                  System.DateTime.Now.Ticks |&gt; string
  
              let asyncUpdate (lbl:Label) (cancelBtn:Button) timeout =
                  async {
                      let result = work timeout //"cancelling" means forcibly aborting, since work may be stuck in an infinite loop
                      do! Async.SwitchToContext guiContext
                      cancelBtn.Enabled &lt;- false
                      lbl.Text &lt;- result
                  }
  
              let parallelAsyncUpdates =
                  [|asyncUpdate lbl1 cancelBtn1 3000; asyncUpdate lbl2 cancelBtn2 6000; asyncUpdate lbl3 cancelBtn3 9000;|]
                  |&gt; Async.Parallel
                  |&gt; Async.Ignore
  
              Async.StartWithContinuations(
                  parallelAsyncUpdates,
                  (fun _ -&gt; startBtn.Enabled &lt;- true),
                  (fun _ -&gt; ()),
                  (fun _ -&gt; ()))
  </code></pre>