2017-01-17 1 views
3

Ich habe diese iterator- Rückgabetyp IEnumerable<Task<Event>> ist so, dass ich später für jedes Element erwarten kann:Await für IEnumerable Artikel, (warten nach await)

private IEnumerable<Task<Event>> GetEventsAsync(long length) 
{ 
    var pos = _reader.BaseStream.Position; 
    while (_reader.BaseStream.Position - pos < length) 
    { 
     yield return ReadEvent(); // this method is async 
    } 
} 

Jetzt möchte ich diesen Konstruktor zu übergeben.

private async Task<EventManager> ReadEventManagerAsync() 
{ 
    // some other stuff 
    var length = Reverse(await _reader.ReadInt32()); // bytes to read 
    var events = GetEventsAsync(length); // cant await iterator. so use linq 
    return new EventManager(events.Select(async e => await e).Select(x => x.Result)); 
} 

Der Konstruktor übernimmt diesen Parameter.

internal EventManager([NotNull, NoEnumeration]IEnumerable<Event> events) {...} 

Wird dieser Code asynchron ausgeführt?

Weil ich nicht in Lambda warten kann, selbst wenn Methode als async markiert ist. Ich habe versucht, etwas zu hacken.

Ich verstehe, warum Select(async e => await e) kehrt IEnumerable<Task<Event>> weil async e => await e Asynchron-Methode ist, die Rückgabetyp innerhalb Task gewickelt werden muss

Meine Frage ist, wird .Select(x => x.Result) noch async laufen? weil ich auf Artikel davor warte, das sollte kein Problem sein, oder? dies sein wie das Schreiben

await e; 
return e.Result; // is it safe? 

Ich will nicht Task.WhenAll verwenden, weil das wird alle Sachen aufzählen, und das ist das, was ich versuche zu vermeiden. Ich möchte diesen Iterator unberührt lassen, bis er im Konstruktor übergeben wird. Ich möchte die Ausführung aufgeschoben halten. (Ich werde Factory-Methode verwenden, wenn dieser Ansatz nicht möglich ist)

+1

Wenn Sie diese Abfrage im Konstruktor nicht aufzählen, wird sie überhaupt nicht ausgeführt. Bitte zeigen Sie den Konstruktorcode –

+0

Ich verstehe, ich lese diese Abfrage im Konstruktor. Ich benutze eine Reihe von selbstgemachten Methoden, so dass es nicht wirklich hilft. Ich habe so etwas wie 'UnknownEvents = events.Sieve (AEvents) .Sieve (BEvents) .ToReadOnlyCollection (x => x); 'das wird alle Dinge aufzählen. @SergeyBerezovskiy –

+0

Ausbeute funktioniert nicht mit erwarten wie erwartet, kann nächste C# Version wird eine bessere Bereitstellung haben. Ab jetzt müssen Sie das Ereignis nur noch in einer Liste abwarten und speichern, werfen Sie einen Blick auf meine Antwort. Auch wenn Ihr ReadEvent von 'Stream.Position' abhängt, können Sie' Task.WhenAll' oder einen anderen Weg nicht verwenden, sondern einfach das Ergebnis in einer Liste auflisten und speichern. –

Antwort

4

Wird dieser Code asynchron ausgeführt?

Nein. Wenn der Enumerable aufgelistet wird, wird er synchron ausgeführt, komplett mit possibility of deadlocks.

Select(async e => await e) tut nichts. Es ist das gleiche wie Select(e => e). Es ist nicht das gleiche wie await e;.

Der gesamte Konvertierungsstrom zu IEnumerable<T> ist extrem merkwürdig.Vielleicht wollten Sie es in IObservable<T> konvertieren?

werde ich Factory-Methode verwenden, wenn dieser Ansatz nicht möglich ist

Ja, Sie nicht await in einem Konstruktor verwenden können, und das Blockieren kann Deadlocks verursachen. Eine asynchrone Fabrikmethode ist wahrscheinlich die beste Wahl.

0

yield funktioniert nicht mit await wie erwartet, möglicherweise nächste C# Version wird eine bessere Bereitstellung haben. Ab sofort müssen Sie das Ereignis in einer Liste abwarten und speichern. Auch wenn Ihr ReadEvent von Stream.Position abhängt, können Sie Task.WhenAll oder einen anderen Weg nicht verwenden, aber einfach auflisten und Ergebnis in Liste speichern.

private async Task<IEnumerable<Event>> GetEventsAsync(long length) 
{ 
    List<Event> events = new List<Event>(); 
    var pos = _reader.BaseStream.Position; 
    while (_reader.BaseStream.Position - pos < length) 
    { 
     // if ReadEvent depends on _reader.BaseStream.Postion 
     // you cannot use Task.WhenAll, because it executes all 
     // tasks in parallel, where else, you must await to finish 
     // your previous ReadEvent 
     Event e = await ReadEvent(); // this method is async 
     events.Add(e); 
    } 
    return events; 
} 
0

können Sie WhenAll für diese, und warten asynchron dafür.

private async Task<EventManager> ReadEventManagerAsync() 
{ 
    // some other stuff 
    var length = Reverse(await _reader.ReadInt32()); // bytes to read 
    var events = GetEventsAsync(length); // cant await iterator. so use linq 
    await Task.WhenAll(events); 
    return new EventManager(events.Select(x => x.Result)); 
} 
+1

'Task.WhenAll' führt jede Operation parallel aus, wodurch' Stream.Position' eine ungültige Position zurückgibt. –

1

Nein, es wird synchron ausgeführt (Konstruktoren können nicht asynchron sein).

Das bedeutet nicht, dass Ihre Leistung beeinträchtigt wird, wenn Sie die Aufgaben nie ausführen. events.Select(async e => await e).Select(x => x.Result) gibt schließlich einen aufzählbaren Wert zurück. Es wird nicht die erste Select aufrufen, was bedeutet, dass der erwartete Code nie aufgerufen wird.

+0

Also wenn ich diesen inneren Konstruktor aufzählen wird es synchron laufen? dann denke ich, dass ich keine andere Wahl habe, als Ergebnisse in der Liste zu speichern, wie @akashkava vorgeschlagen hat und Liste zum Erbauer passiere. –

+0

Wenn Sie es in einer Liste erzwingen, wird der Code bereits ausgeführt. Sie können also nicht sicher sein, ob Sie das möchten. @ M.kazemAkhgary –

+0

Ja. Ich wollte die Dinge cool aussehen lassen (und verhindern, dass zusätzliche Listen erstellt werden, wie auch immer GC es handhaben wird), aber ich denke, das ist alles was ich jetzt tun kann, danke für deine Antwort, ich akzeptiere beide Antworten wenn ich könnte :) –