.net 函数调用一般超时(无任务/取消令牌)

.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

出于用户体验的原因,我不能允许长时间运行的方法。 所有运行时间超过X毫秒的方法都会排队到后台进程(这不是本文的主题)

我正在寻找一种通用的机制,以强制在确定的时间间隔内执行方法/函数

到目前为止,我得出了以下解决方案:

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上使用时,它会释放所有上下文示例
有人知道如何改进CallWithTimeOut函数吗

注意:我不想使用Tasks/cancellationToken方法,因为我无法将令牌传递给该方法,并且即使在超时之后,它仍将运行

编辑:

通过将[Delegate]替换为Func.Invoke()解决了性能问题


仍然无法解决第二个问题

我同意大家的说法,使用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
样式中的事务)。我理解。如果您有现有的代码,对任务进行重构既不像在纸上看起来那么简单,也不是一项短期任务:)。但是,依我看,解决直接使用线程(特别是涉及数据交换时)可能产生的所有实现错误所需的时间并不值得,因为您有一个在内部支持这些操作的成熟替代方案。