.net 函数调用一般超时(无任务/取消令牌)
出于用户体验的原因,我不能允许长时间运行的方法。 所有运行时间超过X毫秒的方法都会排队到后台进程(这不是本文的主题) 我正在寻找一种通用的机制,以强制在确定的时间间隔内执行方法/函数 到目前为止,我得出了以下解决方案:.net 函数调用一般超时(无任务/取消令牌),.net,vb.net,.net,Vb.net,出于用户体验的原因,我不能允许长时间运行的方法。 所有运行时间超过X毫秒的方法都会排队到后台进程(这不是本文的主题) 我正在寻找一种通用的机制,以强制在确定的时间间隔内执行方法/函数 到目前为止,我得出了以下解决方案: Imports System.Threading Module Module1 Public Function CallWithTimeOut(Of T)(timeOut As Integer, dlg As [Delegate]) As T Dim
Imports System.Threading
Module Module1
Public Function CallWithTimeOut(Of T)(timeOut As Integer, dlg As [Delegate]) As T
Dim ret As T
Dim th As Thread
th = New Thread(New ThreadStart(Sub() ret = DirectCast(dlg.DynamicInvoke(), T)))
th.Start()
th.Join(timeOut)
If th.IsAlive Then
th.Abort()
Throw New TimeoutException
End If
Return ret
End Function
Private Function testStr(ByVal str As String) As String
System.Threading.Thread.Sleep(1500)
Return str
End Function
Private Function testInTimeOut(timeOut As Integer, ByVal str As String) As String
Return CallWithTimeOut(Of String)(timeOut, Function() testStr(str))
End Function
Sub Main()
Console.WriteLine(testInTimeOut(2000, "plopTimeOut")) ' OK
Console.WriteLine(testInTimeOut(1000, "plopTimeOut")) ' Exception
Console.ReadKey()
End Sub
End Module
Public Function CallWithTimeOut(Of T)(timeOut As Integer, dlg As Func(Of T), Optional ByVal ctx As System.Web.HttpContext = Nothing) As T
Dim ret As T
Dim th As Thread
th = New Thread(New ThreadStart(Sub()
If Not ctx Is Nothing Then
System.Web.HttpContext.Current = ctx
End If
ret = dlg.Invoke()
End Sub))
th.Start()
th.Join(timeOut)
If th.IsAlive Then
th.Abort()
Throw New TimeoutException
End If
Return ret
End Function
它运行得很好,但我面临一些问题:
- delegate.DynamicVoke因未执行而闻名
- 在动态调用委托内部的代码时,当在webApi或webForm项目HttpContext.Current上使用时,它会释放所有上下文示例
仍然无法解决第二个问题我同意大家的说法,使用Tasks和CancellationToken更好,但是重写所有遗留代码以符合要求太耗时了 事实上,我找到了解决上下文问题的方法,这要归功于 这是我的最终解决方案:
Imports System.Threading
Module Module1
Public Function CallWithTimeOut(Of T)(timeOut As Integer, dlg As [Delegate]) As T
Dim ret As T
Dim th As Thread
th = New Thread(New ThreadStart(Sub() ret = DirectCast(dlg.DynamicInvoke(), T)))
th.Start()
th.Join(timeOut)
If th.IsAlive Then
th.Abort()
Throw New TimeoutException
End If
Return ret
End Function
Private Function testStr(ByVal str As String) As String
System.Threading.Thread.Sleep(1500)
Return str
End Function
Private Function testInTimeOut(timeOut As Integer, ByVal str As String) As String
Return CallWithTimeOut(Of String)(timeOut, Function() testStr(str))
End Function
Sub Main()
Console.WriteLine(testInTimeOut(2000, "plopTimeOut")) ' OK
Console.WriteLine(testInTimeOut(1000, "plopTimeOut")) ' Exception
Console.ReadKey()
End Sub
End Module
Public Function CallWithTimeOut(Of T)(timeOut As Integer, dlg As Func(Of T), Optional ByVal ctx As System.Web.HttpContext = Nothing) As T
Dim ret As T
Dim th As Thread
th = New Thread(New ThreadStart(Sub()
If Not ctx Is Nothing Then
System.Web.HttpContext.Current = ctx
End If
ret = dlg.Invoke()
End Sub))
th.Start()
th.Join(timeOut)
If th.IsAlive Then
th.Abort()
Throw New TimeoutException
End If
Return ret
End Function
调用
Thread.Abort()
是危险的,只有在试图强制退出整个应用程序时才应该调用它。如果您想强制关闭,您应该找到终止线程或使用完整进程的优雅方法。有一个允许指定超时的构造函数(不要遵循那里的代码,请参阅备注部分)。也可以使用CancelAfter()
方法进行设置(如果需要,可导致重置。如果CTS尚未取消)。@Jimi我知道,但如果在调用的代码中未处理cancelationtoken,则该方法的实际执行将根本不会取消。您的应用程序将停止等待结果,但实际工作仍将继续。什么样的操作需要2分钟?异步操作都接受CacellationToken作为参数:Stream ReadAsync
,FileStream.WriteAsync
,SqlConnection.OpenAsync
等。您自己的过程?然后,您可以检查是否已设置了iscancellationrequest
。问题是,你被线程卡住了。继续执行任务。标准代理或lambda优雅地处理取消。(您还有IAsyncResult
样式中的事务)。我理解。如果您有现有的代码,对任务进行重构既不像在纸上看起来那么简单,也不是一项短期任务:)。但是,依我看,解决直接使用线程(特别是涉及数据交换时)可能产生的所有实现错误所需的时间并不值得,因为您有一个在内部支持这些操作的成熟替代方案。