如何在不标记所有方法Async的情况下使用Await Task.Delay?

时间:2014-09-10 21:04:22

标签: c# .net vb.net multithreading asynchronous

我正在努力将使用线程的旧代码替换为基于.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的正确使用是什么?

1 个答案:

答案 0 :(得分:1)

您需要等待的方法应该标记为异步,而不是所有方法。如果你有一个添加Var1 + Var2的简单函数,那么使这种异步变得异常是荒谬的。话虽这么说,你最终会把很多事情做成异步,因为他们会调用一些需要等待的东西。

根据此处的讨论,你可能会更好地使用定时器,这导致你的另一个问题,“Task.Delay的正确使用是什么”?我只使用它,所以我可以等待我的UI完成它正在做的事情。例如,我调用数据库并启动UI转换,以便在接下来的1/2秒内逐步显示屏幕的新部分。我不想在1/2秒内填写我的结果,因为它经常会产生一个紧张的屏幕,所以我等到它完成。执行此操作的简单方法是调用数据库,然后创建延迟,然后使用WhenAll等待最后一个完成。这通常是我的1/2秒,但有时候是数据库。

作为旁注,您可以使用在后台运行的异步调用同步方法。这是一个更容易从线程过渡,但由于你已经改变了大部分代码,你不想在这里。