提问人:Henrik R Clausen 提问时间:7/17/2023 最后编辑:Henrik R Clausen 更新时间:7/18/2023 访问量:44
Threading.Thread.Sleep() 抛出意外异常
Threading.Thread.Sleep() throws unexpected exceptions
问:
在一个大容量(每天 1-200 万个 http 请求)的 Web 应用程序(SCORM 播放器)中,我们有一个队列来优雅地处理峰值负载 - 在峰值负载下,请求可能需要等待 20-50 毫秒才能在应用程序实例之间共享的队列中得到服务。这是下面代码中对 Sleep() 的调用。奇怪的是,偶尔(每天 100-150 次)调用 Sleep() 会抛出一个空引用异常,该异常不会被 try/catch 捕获。我们将其记录到 Application Insights。
- Sleep() 如何抛出这个未记录的异常?Threding.Thread 可以为 null 吗?
- try/catch 怎么会无法捕获异常?
{
"Message":"Object reference not set to an instance of an object.",
"Data":[
],
"InnerException":null,
"TargetSite":"Void WaitInQueue(System.Guid, SCORM.LmsInstance)",
"StackTrace":" at SCORM.API.WaitInQueue(Guid key, LmsInstance instance) in D:\\a\\1\\s\\SCORM\\API.ashx.vb:line 57",
"HelpLink":null,
"Source":"SCORM",
"HResult":-2147467261,
"_typeTag":"NullReferenceException"
}
Private Shared Lock As New Object
Sub ProcessRequest(context As HttpContext) Implements IHttpHandler.ProcessRequest
Dim response As HttpResponse = context.Response
response.ContentType = "text/plain"
Dim myLmsInstance As New LmsInstance With {
.RequestData = New ApiRequestData(context.Request)
}
myLmsInstance.InitializeSessionData()
Dim key As Guid = Guid.NewGuid
MaintainQueue(True, key, myLmsInstance)
WaitInQueue(key, myLmsInstance)
myLmsInstance.HandleApiCall()
MaintainQueue(False, key, myLmsInstance)
response.Write(myLmsInstance.GetResponseData)
End Sub
Private Sub MaintainQueue(addToQueue As Boolean, key As Guid, instance As LmsInstance)
SyncLock Lock
If instance.SessionData IsNot Nothing Then
If addToQueue Then
instance.SessionData.RequestQueue.Add(key)
Else
instance.SessionData.RequestQueue.Remove(key)
End If
Dim NextInQueue = instance.SessionData.RequestQueue.FirstOrDefault
If NextInQueue <> Guid.Empty Then
instance.SessionData.NextInQueue = NextInQueue
Else
instance.SessionData.NextInQueue = Nothing
End If
End If
End SyncLock
End Sub
Private Sub WaitInQueue(key As Guid, instance As LmsInstance)
If instance.SessionData IsNot Nothing Then
Try
Dim NextInQueue = instance.SessionData.NextInQueue
While NextInQueue.HasValue AndAlso NextInQueue.Value <> key
' Sleep as briefly as possible. The default on a Windows server is 15 ms.
Threading.Thread.Sleep(1)
NextInQueue = instance.SessionData.NextInQueue
End While
Catch ex As Exception
Serilog.Log.Logger.Warning(ex, "Exception in SCORM Player, WaitInQueue(): {@ex}", ex)
End Try
End If
End Sub
最近添加了 try/catch,期望处理异常并为我们提供日志记录。但是异常仍未处理,永远不会到达 Logger.Warning() 代码。
答:
0赞
Henrik R Clausen
7/17/2023
#1
我想我明白了(在高负载下等待验证):
Threading.Thread.Sleep(1) 是错误的,我缺少我的 Imports 语句。我将其更正为以下内容:
导入 System.Threading
线程睡眠(1)
评论
3赞
djv
7/17/2023
Threading.Thread.Sleep(1)
应该不会错。这两个选项都指向相同的命名空间和函数。实际上,在调用中包含更多命名空间通常是消除调用中歧义的一种方式,因此我看不出您的编辑实际上可以改进任何内容。你能解释一下为什么你认为这将解决问题吗?
评论
NextInQueue = instance.SessionData.NextInQueue
SessionData
NextInQueue
async
await Task.Delay