2017-01-13 3 views
5

Dies ist etwas, für das ich immer Threads/BackgroundWorker verwendet habe, aber ich versuche, zu Task-Weg zu migrieren.Kontinuierliches Polling mit Tasks

Angenommen, ich verwende ein SDK von einem Drittanbieter, das ich zum Lesen von Bytes von einem USB-Anschluss verwende. Dieser Leseaufruf blockiert und endet nach 100 ms, wenn keine Bytes gelesen werden und gibt null zurück. Es kehrt sofort zurück, wenn Bytes gelesen werden, wobei Byte [] Array von gelesenen Bytes zurückgegeben wird.

Also muss ich im Grunde polling wieder und wieder, und Maßnahmen für empfangene Bytes, indem Sie Parsing-Funktion aufrufen. Es ist eine WPF-Anwendung, daher sollten die zurückgegebenen Bytes an eine UI-Thread-Funktion übergeben werden können.

Was ist der richtige Ansatz dafür? Das ist, was ich habe so weit, und es scheint zu funktionieren, aber ich möchte sicherstellen, dass es der richtige Weg, Dinge zu tun TPL mit:

private void _connectUsbButton_Click(object sender, RoutedEventArgs e) 
{ 
    ListenForUsbMessagesAsync(); 
} 

private async void ListenForUsbMessagesAsync() 
{ 
    while (true) 
    { 
     byte[] readBytes = await ReadBytesAsync(); 
     Parse(readBytes); 
    } 
} 

private Task<byte[]> ReadBytesAsync() 
{ 
    Task<byte[]> readBytesTask = Task.Run(() => 
    { 
     byte[] bytes; 

     do 
     { 
      bytes = ReadBytes(); 
     } while (bytes == null); 

     return bytes; 
    }); 

    return readBytesTask; 
} 

private byte[] ReadBytes() 
{ 
    byte[] readBytes = _usbSdk.ReadBytes(); //100ms timeout (returns null if no bytes read) 
    return readBytes; 
} 
+0

'Aufgabe ' für einen eventuellen Ergebnis ist, nicht eine, die regelmäßig geschieht. –

+0

@ DanielA.White das ist, warum ich es in der while (true) Schleife anrufe. Das letztendliche Ergebnis ist, dass einige Bytes gelesen werden. Die Bytes werden nicht die ganze Zeit gelesen, tatsächlich werden meistens keine Bytes gelesen. – Eternal21

+0

Warum hast du 'Thread' für diese Art von Aufgabe nicht gemocht? 'Aufgaben sind so konzipiert, dass sie schnell abgeschlossen werden, während Ihr IO Minuten dauern kann. – slawekwin

Antwort

4

mir sieht nicht gut aus, nur ein paar Vorschläge hier:

private async Task ListenForUsbMessagesAsync(CancellationToken token) 
{ 
    while (true) 
    { 
     byte[] readBytes = await ReadBytesAsync(); 
     Parse(readBytes); 
     token.ThrowIfCancellationRequested(); 
    } 
} 

Irgendwo anders, wie in WPF-Fenster .ctor speichern diese

var tokenSource = new System.Threading.CancellationTokenSource(); 

Schließlich Ihre Funktion wie diese

anrufen Auf diese Weise

können Sie Ihre Aufgabe in jedem Moment abbrechen, indem

Aufruf
tokenSource.Cancel() 

Alternativ, wenn Sie wollen Aufgaben nicht verwenden, können Sie einen neuen Thread erzeugen und im Dispatcher Objekt übergeben. Auf diese Weise kann der neu erstellte Thread Objekte sicher auf den UI-Thread übertragen.

5

Da Ihre Abfrage-Task möglicherweise lange Zeit ausgeführt wird, sollten Sie darüber nachdenken, sie in einem dedizierten Thread auszuführen.

können Sie dies erreichen, indem Sie ein Flag TaskCreationOptions.LongRunning beim Erstellen der Abfrage-Aufgabe übergeben.

wie folgt aus:

Task<byte[]> readBytesTask = Task.Factory.StartNew(() => 
    { 
     byte[] bytes; 

     do 
     { 
      bytes = ReadBytes(); 
     } while (bytes == null); 

     return bytes; 
    }, TaskCreationOptions.LongRunning); 
+0

Versucht, Ihren Vorschlag hinzuzufügen, aber es endet mit einem Compiler-Fehler in der 'Return-Bytes' Zeile, die besagt: CS0029 \t Kann Typ 'Byte []' nicht implizit in 'System.Threading.Tasks.Task' – Eternal21

+1

behoben werden, müssen Sie Verwenden der Task.Factory um eine TaskCreationOptions zu übergeben (vergiss diese Überladung ist nur unter der Factory verfügbar) – barakcaf