2017-07-27 3 views
1

Hallo, ich habe Textbox, die Text Ereignis geändert hat. Jedes Mal, wenn ein Zeichen in ein Textfeld eingefügt wird, wird das Textänderungsereignis ausgelöst. Das Ereignis Text change ruft eine asynchrone Task-Methode auf. Unten finden Sie die Methode my event und async Task.So stellen Sie sicher, async Aufgabe Methodenaufrufe wird synchron ausgeführt

public Textbox_TextChangedEvent() 
    { 
     GetStocks(texboxText); 
    } 

public async Task GetStocks(string texboxText) 
    { 
     IsBusy = true; 
     await Task.Run(() => { CreateCollection(texboxText); }); 
     IsBusy = false; 
    } 

Frage Wie kann ich sicherstellen, dass GetStocks Methode synchron nacheinander aufgerufen wird.

Beispiel Angenommen, Benutzer hat Eingang Ted als Eingabetext. Dann möchte ich, dass der Async-Aufruf nacheinander abgeschlossen wird. d. H. Es sollte GetStocks in der folgenden Reihenfolge aufrufen und die Aufgabe in der folgenden Reihenfolge selbst abschließen.

  1. GetStocks (T)
  2. GetStocks (Te)
  3. GetStocks (Ted)
+0

Wie ist das gewünschte Verhalten anders als das aktuelle Verhalten? –

+0

Welchen Rahmen verwenden Sie? Ist das eine Desktop-App oder eine Web-App? – Michael

+0

aaah Wenn Sie die Arbeit anstehen möchten, verwenden Sie eine Warteschlange, um die auszuführende Arbeit zu speichern, und bearbeiten Sie sie dann in der Reihenfolge – user230910

Antwort

-1

Eine einfache Möglichkeit, abhängig von der Situation sein könnte:

public async Task GetStocks(string texboxText) 
{ 
    Task.Run(() => { 
     IsBusy = true; 
     CreateCollection(texboxText); 
     IsBusy = false; 

    }); 
} 
+0

Entschuldigung, der obige Code funktionierte nicht für mich. Eigentlich ist das Problem, das ich hier bin. In der Reihenfolge, die in meiner Frage erwähnt wird, werden drei asynchrone Anrufe gemacht, 1.GetStocks (T) 2.GetStocks (Te) 3.GetStocks (Ted). Aber die Reihenfolge, in der ich das Ergebnis zurückbekomme, ist 3,2,1. Aber ich möchte, dass das Ergebnis in folgender Reihenfolge zurückkommt: 1,2,3 – Vinay

0

zu lösen Probleme wie diese haben wir verwendet AsyncLock vorherige Projekte. Die AsyncLock wartet, bis die vorherige Sperre aufgehoben wurde.

Die AsyncLock mag zuerst ein wenig kompliziert erscheinen, aber ich hoffe, dass die mitgelieferten Anwendungsbeispiele sein Verhalten veranschaulichen.

public class AsyncLock 
{ 
    private TaskCompletionSource<object> _lastSection; 

    public AsyncLock() 
    { 
     _lastSection = new TaskCompletionSource<object>(); 
     _lastSection.SetResult(null); 
    } 

    public class ReleaseLock : IDisposable 
    { 
     private readonly TaskCompletionSource<object> _tcs; 

     public ReleaseLock(TaskCompletionSource<object> tcs) 
     { 
     _tcs = tcs; 
     } 

     public void Dispose() 
     { 
     _tcs.SetResult(null); 
     } 
    } 

    /// <summary> 
    /// Enters and locks a critical section as soon as the currently executing task has left the section. 
    /// The critical section is locked until the returned <see cref="IDisposable"/> gets disposed. 
    /// </summary> 
    public Task<ReleaseLock> EnterAsync() 
    { 
     var newTcs = new TaskCompletionSource<object>(); 
     var toAwait = Interlocked.Exchange(ref _lastSection, newTcs); 
     return toAwait.Task.ContinueWith((_) => new ReleaseLock(newTcs), TaskContinuationOptions.ExecuteSynchronously); 
    } 
} 

Sie können dann await AsyncLock.EnterAsync() warten verwenden, bis eine frühere Sperre freigegeben wurde. In der EnterAsync Warteschlange wir die nächste Task nach der aktuellen Task mit ContinueWith. Dies bedeutet, dass die await AsyncLock.EnterAsync() ausgeführt wird, nachdem die vorherige beendet wurde. Hier

using (await _lock.EnterAsync()) 
{ 
    // ... 
} 

ist ein Anwendungsbeispiel:

class Program 
{ 
    private static readonly AsyncLock _lock = new AsyncLock(); 

    private static async Task Test(int i, Task toComplete) 
    { 
     using (await _lock.EnterAsync()) 
     { 
     await toComplete; 
     Console.WriteLine(i); 
     } 
    } 

    public static void Main(string[] args) 
    { 
     var tcs1 = new TaskCompletionSource<object>(); 
     var tcs2 = new TaskCompletionSource<object>(); 

     Task.Run(async() => 
     { 
     var t1 = Test(1, tcs1.Task); // start first task 
     var t2 = Test(2, tcs2.Task); // start second task 

     tcs2.SetResult(null); // finish second first 
     tcs1.SetResult(null); // fiish last task 

     await Task.WhenAll(t1, t2); // will print: 1 and then 2 
     }).Wait(); 
    } 
} 

Die Test Methode nimmt zunächst die Async Sperre eingeben, warten dann die Aufgabe toComplete und dann auf die Konsole schreiben.

Wir beginnen zwei Test Aufgaben ("1" und "2") und die zweite toComplete erste abzuschließen. Ohne das AsyncLock druckt das vorherige Beispiel: "2", "1". Mit der AsyncLock werden die Aufgaben jedoch in der Reihenfolge bearbeitet, in der sie gestartet wurden.

BEMERKUNGEN: Eine letzte Bemerkung. Dies wird Ihre Bearbeitungsreihenfolge erreichen, kann aber manchmal schwierig sein. Wenn Sie solche Sperren verwenden, kann dies leicht zu Deadlocks führen, die schwer zu lösen und schwer zu finden sind. Verwenden Sie Schlösser sehr vorsichtig.

EDIT: Hier ein Anwendungsbeispiel Sie Ihr Problem:

private readonly AsyncLock _lock = new AsyncLock(); 

public Textbox_TextChangedEvent() 
{ 
    GetStocks(texboxText); // every call is now "queued" after the previous one 
} 

public async Task GetStocks(string texboxText) 
{ 
    using(await _lock.EnterAsync()) 
    { 
     IsBusy = true; 
     await Task.Run(() => { CreateCollection(texboxText); }); 
     IsBusy = false; 
    } 
} 
+0

Das 'ContinueWith' in' EnterAsync' ist seltsam. "NewTcs" als Status übergeben, nur um vom Delegaten ignoriert zu werden? Das ist wie ein Versuch, das Schließen einer lokalen Variablen zu vermeiden, die auf halbem Wege aufgegeben wurde. Erinnert mich an diese 'AsyncLock'-Version (außer diese verwendet tatsächlich den Status): https://blogs.msdn.microsoft.com/pfxteam/2012/02/12/building-async-coordination-primitives-part-6- asynclock /) –

+0

@KirillShlenskiy Sie haben Recht. Habe den Code von einem alten Silverlight-Projekt erhalten, wo dieser Parameter nicht optional war. Wird die Antwort aktualisieren. – Iqon

Verwandte Themen