我正在努力将使用线程的旧代码替换为基于.NET 4.5 Task的系统。
我用Tasks替换了线程,接下来我正在用Await Task.Delay替换我的Thread.Sleep调用。我遇到的问题是无法在Synclock部分中调用await,现在使用Await Task.Delay的每个方法都需要标记为Async。
我可以绕过synclock问题,因为我只有几个块,可以用更好的代码替换。但是,必须标记每个方法Async会导致问题。这意味着我必须标记调用该方法Async的方法,依此类推。最终我的所有方法都将是异步。
这是在使用基于任务的方法时应该如何完成的,还是我做错了?
编辑1:发布示例代码
Public Async Function Delay(Milliseconds As Integer, Optional Initial As Boolean = False, Optional Silent As Boolean = False, Optional Modifier As Double = 0.3, _
Optional Task As Task = Nothing, Optional ExitOnTaskStop As Boolean = True) As Tasks.Task(Of Boolean)
Dim OutputBufferKey As String = Nothing
If Task IsNot Nothing Then
If Task.StopRequested Then Return True
OutputBufferKey = Task.OutputBufferKey
End If
If Initial Then
Milliseconds = Rand.Next(0, Milliseconds)
ElseIf Modifier > 0 Then
Dim MinValue As Integer = CInt(Milliseconds * (1 - Modifier))
Dim MaxValue As Integer = CInt(Milliseconds * (1 + Modifier))
If MinValue < MaxValue Then Milliseconds = Rand.Next(MinValue, MaxValue + 1)
End If
If DebugMode AndAlso Not Silent Then
Dim LengthString As String = Nothing
Select Case Milliseconds
Case Is < 60 * 1000 : LengthString = Math.Round(Milliseconds / 1000, 1) & " seconds"
Case Is < 60 * 60 * 1000 : LengthString = Math.Round(Milliseconds / (60 * 1000), 1) & " minutes"
Case Else : LengthString = Math.Round(Milliseconds / (60 * 60 * 1000), 1) & " hours"
End Select
Output(OutputBufferKey, "Sleeping for " & LengthString)
End If
If ExitOnTaskStop AndAlso Task IsNot Nothing Then
Try
Await Tasks.Task.Delay(Milliseconds, Task.CancellationToken.Token)
Catch ex As OperationCanceledException
Return True
End Try
Else
Await Tasks.Task.Delay(Milliseconds)
End If
Return False
End Function
我需要延迟有很多原因,并且该方法在许多其他方法中被调用。举几个例子,我有一些代码,使用OpenPop DLL来检查收件箱中是否有邮件到达,如果在第一次检查时没有,我需要等待再次检查,我有循环和睡眠,如果没有已被发现。另一个例子是我需要创建一个HttpWebRequest来检查文件,如果内容没有改变,我想在30秒内再次执行此操作。
我想使用计时器会更好吗?如果是这样,Task.Delay的正确使用是什么?
答案 0 :(得分:1)
您需要等待的方法应该标记为异步,而不是所有方法。如果你有一个添加Var1 + Var2
的简单函数,那么使这种异步变得异常是荒谬的。话虽这么说,你最终会把很多事情做成异步,因为他们会调用一些需要等待的东西。
根据此处的讨论,你可能会更好地使用定时器,这导致你的另一个问题,“Task.Delay的正确使用是什么”?我只使用它,所以我可以等待我的UI完成它正在做的事情。例如,我调用数据库并启动UI转换,以便在接下来的1/2秒内逐步显示屏幕的新部分。我不想在1/2秒内填写我的结果,因为它经常会产生一个紧张的屏幕,所以我等到它完成。执行此操作的简单方法是调用数据库,然后创建延迟,然后使用WhenAll
等待最后一个完成。这通常是我的1/2秒,但有时候是数据库。
作为旁注,您可以使用在后台运行的异步调用同步方法。这是一个更容易从线程过渡,但由于你已经改变了大部分代码,你不想在这里。