2017-08-26 4 views
2

Zuerst suchte ich hier und habe viele ähnliche Fragen gesehen, aber keine von ihnen ist was ich will.Ist das eine gute Praxis für das asynchrone Arbeiten?

Ich habe eine Funktion, die einige Zeit einen Wert zurückgeben nimmt zu vereinfachen, lassen Sie uns sagen, es ist: es laufen

Private Function longProcess() As Boolean 
    Threading.Thread.Sleep(10000) 
    Return True 
End Function 

ich will und seinen Wert zu erhalten, lassen Sie uns Button1

auf klicken sagen

ich habe versucht, den folgenden Code und es funktioniert perfekt

Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 
    'some stuff 
    Dim output As Boolean = Await Task.Run(Of Boolean)(Function() longProcess()) 
    'continue another stuff when the longProcess completes 
End Sub 

Wenn auf diese Weise gut genug ist? wenn nicht, welche Probleme hat es vielleicht?

ich einen anderen Weg wurde mit, aber es machte die CPU-Auslastung höher wegen Application.DoEvents()

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 
    'some stuff 
    Dim awaiter = Task.Run(Of Boolean)(Function() longProcess()).GetAwaiter() 
    Do While Not awaiter.IsCompleted 
     Application.DoEvents() 
    Loop 
    Dim output As Boolean = awaiter.GetResult() 
    'continue another stuff when the longProcess completes 
End Sub 
+1

Haben Sie Probleme, wenn Sie die erste Option verwenden? Wenn Sie es nicht weiter verwenden, bis Sie einige Probleme haben. – Fabio

+0

Keine Probleme mit Code zu haben bedeutet nicht, dass es in Ordnung ist. Ich frage, ob es technisch gut ist oder es einen besseren kurzen Weg gibt. – Youssef13

+0

Was Sie erwarten, "kürzer" als eine Zeile Code zu sein. Mit Ihrer ersten Option führen Sie die Funktion für einen anderen Thread aus, der im UI-Client-Ereignishandler korrekt abgewartet wurde. Wenn also die erste Option nicht gegen Ihre Anforderungen verstößt, können Sie sie weiterhin verwenden. Für den Fall, dass eine Long Running-Funktion einige externe Ressourcen (Fily-System, Datenbank, Webdienste usw.) verwendet, ist die erste Option keine bewährte Methode, da auf externe Ressourcen mit 'async-await' effektiver zugegriffen werden kann, ohne zusätzliche Threads zu verwenden. – Fabio

Antwort

4

Basierend auf den Kommentaren, dass Ihre „long running“ Funktion sendet HTTP-Anforderung, sollten Sie verwenden Sie "vollständig" asynchronen Ansatz ohne zusätzliche Threads zur Verfügung gestellt von Task.Run

Private Async Function SendRequest() As Task(Of Boolean) 
    Using (client As New HttpClient()) 
     client.BaseAddress = new Uri("http://your:api/") 

     Dim response As HttpResponseMessage = Await client.GetAsync(pathToResource) 

     Return response.IsSuccessStatusCode 
    End Using 
End Function 

Dann klicken

Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 
    'some stuff 
    Dim output As Boolean = Await SendRequest() 
    'continue another stuff when the longProcess completes 
End Sub 

Oben Ansatz ist besser als Ihre, die Task.Run verwendet, weil, wenn Sie Anfrage von einem anderen Thread senden, that Thread nichts tun, sondern nur auf Antwort warten. Wo die asynchronen async-await Methoden von HttpClient (oder einer anderen Klasse) verwendet werden, wird die gesamte Arbeit an einem Thread ausgeführt, ohne den Haupt-UI-Thread der Anwendung zu blockieren.

Hinweis über HttpClient: Auch in der obigen Beispielinstanz HttpClient, die in Using Block verwendet wird, sollten Sie nur eine Instanz für Ihre Anwendungslebensdauer verwenden.

Von Microsoft docs:

Httpclient soll einmal instanziiert werden und während die Lebensdauer einer Anwendung wiederverwendet. Vor allem in Serveranwendungen führt das Erstellen einer neuen HttpClient-Instanz für jede Anforderung die Anzahl der unter schweren Lasten verfügbaren Sockets aus. Dies führt zu SocketException-Fehlern.

+0

Danke für deine Antwort. Ich verwende HttpWebRequest, nicht HttpClient. Ich weiß wirklich nicht, wie Sie Ihr Codebeispiel bearbeiten, um mit HttpWebRequest zu arbeiten. Ich schätze es, wenn Sie es bearbeitet haben. Ich hoffe auch, du erzählst mehr darüber, warum dieser Weg besser ist als meiner und was meinst du mit "voll" asynchron. – Youssef13

+1

@ Youssef13, können Sie diese Antwort nützlich finden, gibt es weitere Links zur Verfügung gestellt über HttpClient - [https://Stackoverflow.com/a/27737601/1565525](https://Stackoverflow.com/a/27737601/1565525) – Fabio

+0

Danke für die Antwort :) Ich könnte es mit HttpWebRequest tun, gibt es GetResponseAsync() -Methode Aber ich frage mich immer noch, warum dies besser ist als mit Task.Run – Youssef13

3

Ich würde sagen, es ist eine Standard-Praxis. Sie könnten auch die lange Funktion machen async auch

Private Async Function longProcessAsync() As Task(Of Boolean) 
    Await Task.Delay(10000) ' Simulating web service call 
    Return True 
End Function 

und warten auf sie in der Event-Handler

Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 
    'some stuff 
    Dim output As Boolean = Await longProcessAsync() 
    'continue another stuff when the longProcess completes 
End Sub 

Referenz: Async/Await - Best Practices in Asynchronous Programming

Async All the Way

..."Async all the way" bedeutet, dass Sie synchronen und asynchronen Code nicht mischen sollten, ohne die Konsequenzen sorgfältig zu berücksichtigen.

...

erlauben async durch die Code-Basis zu wachsen ist die beste Lösung, aber das bedeutet eine Menge erster Arbeiten für eine Anwendung gibt es wirklichen Nutzen von Asynchron-Code zu sehen. Es gibt einige Techniken, um eine große Codebasis inkrementell in asynchronen Code zu konvertieren, aber sie fallen nicht in den Anwendungsbereich dieses Artikels. In einigen Fällen kann die Verwendung von Task.Wait oder Task.Result bei einer teilweisen Konvertierung helfen, Sie müssen jedoch sowohl das Deadlock-Problem als auch das Fehlerbehandlungsproblem beachten.

Verwandte Themen