2014-09-10 59 views
0

我正致力于将使用线程的旧代码替换为基于.NET 4.5任务的系统。如何在不标记所有方法异步的情况下使用Await Task.Delay?

我已经用任务替换了线程,接下来我正在用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

“我用Tasks替换了线程,接下来我正在用Await Task.Delay替换Thread.Sleep调用。”为什么? – Sam 2014-09-10 21:08:26

+0

你为什么叫'Thread.Sleep'?如果你在整个代码的随机地方使用它,你很可能做错了。将业务逻辑与任务调度逻辑分开。而且你实际上不需要替换所有'Thread.Sleep'的调用,但这取决于用法。 – Athari 2014-09-10 21:11:37

+0

@Sam我以前的做法是创建数千个线程,我被告知使用任务是更好的方式。至于Thread.Sleep,Task.Delay似乎有所改进,因为我可以给它取消令牌,所以我不必Thread.Sleep(100),检查取消并再次循环。这些最近的问题可能会更好地解释我是如何到达这里的。 https:// stackoverflow。com/questions/25764970/should-i-use-asynchronous-methods-within-a-background-thread http://stackoverflow.com/questions/25773587/how-do-i-deal-without-byref-in- an-async-function/25773634 – iguanaman 2014-09-10 21:12:40

回答

1

您需要等待的方法应该标记为异步,而不是一切。如果你有一个简单的函数,增加了Var1 + Var2,那么做出异步将是荒谬的。话虽如此,你最终会做很多异步的事情,因为他们会调用某些需要等待的东西。

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

作为一个方面说明,您可以调用同步方法使用异步,也可以在后台工作。这是一个比线程更容易的转换,但是因为你已经改变了大部分代码,所以你不想在这里。

相关问题