2014-09-10 61 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秒,但有時候是數據庫。

作爲一個方面說明,您可以調用同步方法使用異步,也可以在後臺工作。這是一個比線程更容易的轉換,但是因爲你已經改變了大部分代碼,所以你不想在這裏。

相關問題