取消 Task.Run 个作业

Cancel Task.Run job

我有 async 方法,如下所示。当用户决定停止工作时,我希望有可能 cancel 它。我怎么能在新按钮中做到这一点 CancelUpdate_Click

    Private Async Sub btnUpdate_Click(sender As Object, e As EventArgs) Handles btnUpdate.Click
            Await DoWorkAsync()
    End Sub
    
    Private Function DoWorkAsync() As Task(Of List(Of Vals))
                Return _
                    Task.Run(
                        Async Function() _
                                _migrator.PrepareMigration(CInt(Invoke(New Func(Of Integer)(Function() lbNumms.SelectedValue))), CInt(Invoke(New Func(Of Integer)(Function() lbPro.SelectedValue)))))
    End Function
    
Private Sub CancelUpdate_Click(sender As Object, e As EventArgs) Handles CancelUpdate.Click
            'Stop DoWorkAsync if running
    End Sub

更新:

Private _tokenSource As New CancellationTokenSource()
        Private ReadOnly _token = _tokenSource.Token

Private Async Sub btnUpdate_Click(sender As Object, e As EventArgs) Handles btnUpdate.Click
     Try
        Private ReadOnly _tokenSource As New CancellationTokenSource()
    Private ReadOnly _token = _tokenSource.Token
            Await DoWorkAsync()
        Catch oe As OperationCanceledException
                MessageBox.Show("Task has been cancelled")
      Finally
        _tokenSource.Dispose()
      End Try
    End Sub
        
        Private Function DoWorkAsync() As Task(Of List(Of Vals))
                    Return _
                        Task.Run(
                            Function()
                                Dim tokenSource = New CancellationTokenSource()
                                Dim token = tokenSource.Token
                                Return _migrator.PrepareMigration(CInt(Invoke(New Func(Of Integer)(Function() lbNumms.SelectedValue))), CInt(Invoke(New Func(Of Integer)(Function() lbProducent.SelectedValue))), _token)
                            End Function)
        End Function
            
        
        Public Function PrepareMigration(value1 As Integer, value2 As Integer, cancellationToken As CancellationToken) As List(Of Vals))
        
        cancellationToken.ThrowIfCancellationRequested() 
        MethodA()
        cancellationToken.ThrowIfCancellationRequested()
        MethodB()
        
        End Function
        
        Private Sub btnCancel_Click(sender As Object, e As EventArgs) Handles btnCancel.Click
                      _tokenSource.Cancel()
        End Sub

取消并不是神奇的事情。它必须明确编码。在这种情况下,您的 PrepareMigration 例程需要采用 CancellationToken 参数 并且 需要定期检查该参数的 IsCancellationRequested 属性 已设置为 True.

这样做的一个捷径是定期调用令牌上的 ThrowIfCancellationRequested;如果设置了 属性,这将导致 OperationCanceledException

如果您的日常工作 return 是 Task,您可以 return Task.FromCanceled.

你会得到 CancellationTokenCancellationTokenSource 传入。然后取消按钮的事件处理程序将在源上调用 Cancel 以发出已发出令牌的信号。

例如,如果您的处理涉及多个步骤,可能会像这样工作:

'Include other parameters as appropriate.
Sub PrepareMigration(ByVal token As CancellationToken)
    DoStep1()

    token.ThrowIfCancellationRequested()
    DoStep2()

    '...

    token.ThrowIfCancellationRequested()
    DoStepn()
End Sub

或者,如果您要处理一组项目,可能看起来像这样:

Sub PrepareMigration(ByVal token As CancellationToken)
    For Each item In itemsToProcess
        token.ThrowIfCancellationRequested()
        DoTheItem(item)
    Next
End Sub

根据需要混合搭配。如果在特定步骤中调用的例程特别是 long-running,则该例程本身可能需要是 cancellation-aware.

最终,检查的位置取决于计算步骤的详细信息(包括可能的“快速”与“慢速”步骤)以及您要对用户必须等待多长时间设置的限制请求取消生效。