我在HTTPHandler中有一个长时间运行的进程,我使用Async Await异步执行.net 4.5
这完全符合预期......
如何添加超时,以便在进程耗时太长时返回字符串'timeout'?
Protected Async Sub button1_Click(sender As Object, e As System.EventArgs)
Dim asyncHandler = New AsyncHandler
Await asyncHandler.ProcessRequestAsync(HttpContext.Current)
Response.Write(asyncHandler.Result)
End Sub
Public Class AsyncHandler
Inherits HttpTaskAsyncHandler
Public Property Result As String
Public Async Function ProcessRequestAsync(context As HttpContext) As Task
Me.Result = Await DoLongRunningProcessAsync(context)
End Function
Private Function DoLongRunningProcessAsync(context As HttpContext) As Task(Of String)
'TODO: add a timeout so that if this takes too long we return "timeout":
Return Task.Run(Of String)(Function() DoLongRunningProcess(context))
End Function
Private Function DoLongRunningProcess(context As HttpContext) As String
'perform long running process....
Return "success"
End Function
End Class
答案 0 :(得分:4)
以下是我最终实施的内容:
创建一个具有超时值x毫秒
的CancellationToken添加了一个try catch来捕获错误:OperationCanceledException
Public Async Function ProcessRequestAsync(context As HttpContext) As Task
Dim cts As CancellationTokenSource = New CancellationTokenSource(30000) 'eg: 30 seconds
Try
Me.ResultCode = Await DoLongRunningProcessAsync(HttpContext.Current, cts.Token)
Catch ex As OperationCanceledException
Me.ResultCode = "timeout"
End Try
End Function
将CancellationToken传递给DoLongRunningProcessAsync方法的签名
通过调用ThrowIfCancellationRequested
来检测超时Private Function DoLongRunningProcessAsync(context As HttpContext, ct As CancellationToken) As Task(Of String)
Return Await Task.Run(Of String)(
Function()
Dim resultCode As String = DoLongRunningProcess(context)
'detect timeout:
ct.ThrowIfCancellationRequested()
Return resultCode
End Function)
End Function
这是一篇很棒的文章,我发现它真有帮助:
Async in 4.5: Enabling Progress and Cancellation in Async APIs
答案 1 :(得分:2)
我没有打结VB.NET,但我通常在C#中这样做,如下例所示:
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
// Make sure that we have a way to cancell long running
Task<SomeClass> longRunningTask = GetSomethingAsync(cancellationTokenSource.Token);
// One of the task should be finished
if (longRunningTask == await Task.WhenAny(longRunningTask, Task.Delay(30000)))
{
// Long running task completed
SomeClass result = await longRunningTask;
}
else
{
// Task.Delay(30000) was finished
cancellationTokenSource.Cancel();
}
答案 2 :(得分:0)
正常情况下,支持超时的TPL代码通过@outcoldman和@StephenCleary提到的CancellationToken(Source)来实现。但是,在您的方案中,您说您希望超时路径也返回一个字符串,只是另一个字符串。
因此,不是使用CancellationToken(Source),而是将超时代码视为另一个生成字符串的任务,然后选择任何任务(超时任务或“实际”任务)完成的任务,这可能更简单。返回那个字符串。
我将您的DoLongRunningProcess(最里面的函数)更改为异步并返回Task(Of String),这样您就不必使用Task.Run了。
'Await Await'可能看起来很奇怪,但是Task.WhenAny返回一个Task(Of Task(Of T)),所以第一个Await是到达先完成的特定Task,然后我们等待它得到实际的字符串结果。
Sub Main
MainAsync().Wait()
End Sub
' Define other methods and classes here
Public Async Function MainAsync As Task
Dim asyncHandler = New AsyncHandler
Await asyncHandler.ProcessRequestAsync(System.Web.HttpContext.Current)
Console.WriteLine(asyncHandler.Result)
End Function
Public Class AsyncHandler
Inherits HttpTaskAsyncHandler
Public Property Timeout As TimeSpan = TimeSpan.FromSeconds(10)
Public Property Result As String
Public Overrides Async Function ProcessRequestAsync(context As HttpContext) As Task
Me.Result = Await DoLongRunningProcessAsync(context)
End Function
Private Async Function DoLongRunningProcessAsync(context As HttpContext) As Task(Of String)
'TODO: add a timeout so that if this takes too long we return "timeout":
Dim workerTask As Task(Of String) = DoLongRunningProcess(context)
Dim cancelTask As Task(Of String) = DoTimeout()
Return Await Await Task.WhenAny(workerTask, cancelTask)
End Function
Private Async Function DoTimeout() As Task(Of String)
Await Task.Delay(Timeout)
Return "timeout"
End Function
Private Async Function DoLongRunningProcess(context As HttpContext) As Task(Of String)
'perform long running process....
Await Task.Delay(TimeSpan.FromSeconds(15))
Return "success"
End Function
End Class