2016-12-30 2 views
1

Ich versuche, Rx Stream/beobachtbare Zusammenführung mit Hack Async zu implementieren, und ein Kernschritt wird durch den Titel beschrieben. Eine Code-Version dieser Schritt würde wie folgt aussehen:Konvertieren einer Sammlung von Erwarteter in einen zeitgesteuerten AsyncGenerator in Hack

<?hh // strict 
async function foo(Awaitable<Iterable<T>> $collection): Awaitable<void> { 
    $ordered_generator = async_collection_to_gen($collection) // (**) 
    foreach($ordered_generator await as $v) { 
    // do something with each awaited value in the time-order they are resolved 
    } 
} 

jedoch, nachdem es über grübelt, ich glaube nicht, dass ich kann die Lieblings (**) Funktion schreiben. Ich habe festgestellt, dass die Implementierungen, die ich ausprobiert habe, irgendwann die gleiche Funktionalität wie JS Promise.race benötigen, die löst, wenn der erste einer Sammlung Promises auflöst/ablehnt. Alle Hack's Awaitable collection helpers erstellen jedoch eine von einer vollständig aufgelöste Sammlung. Desweiteren erlaubt Hack nicht, dass wir keine await Async-Anrufe von async function s haben, die ich auch für nötig befunden habe.

Ist es jemandes Wissen möglich?

Antwort

0

Dies ist tatsächlich möglich! Ich grub mich um und stolperte über a fork of asio-utilities von @jano, indem ich eine AsyncPoll Klasse implementierte. See PR for usage. Es tut genau so, wie ich es mir erhofft hatte.

So stellt ich heraus, da ein AwaitableConditionWaitHandle mit succeed und fail Methoden aufgerufen wird *, die von jedem Kontext aufgerufen werden können (so long as the underlying WaitHandle hasn't expired yet) und zwingen die ConditionWaitHandle mit den übergebenen Werten zu lösen.

Ich gab dem Code ein hartes Aussehen, und darunter alles funktioniert es durch aufeinanderfolgende Awaitable Rennen, die ConditionWaitHandle erlaubt. Genauer gesagt wird die Sammlung von Awaitables komprimiert über (aka \HH\Asio\v), die so langsam wie die langsamste Awaitable, dann verschachtelte innerhalb einer ConditionWaitHandle. Jede Awaitable wird in einer async function erwartet, die die gemeinsame ConditionWaitHandle auslöst und das Rennen beendet. Dies wird wiederholt, bis die Awaitable s alle aufgelöst haben.

Hier ist eine kompaktere Implementierung eines Rennens die gleiche Philosophie mit:

<?hh 
function wait(int $i): Awaitable<void> { 
    return Race::wrap(async { await HH\Asio\usleep($i); return $i; }); 
} 
// $wait_handle = null; 
class Race { 
    public static ?ConditionWaitHandle $handle = null; 
    public static async function wrap<T>(Awaitable<T> $v): Awaitable<void> { 
     $ret = await $v; 
     $handle = self::$handle; 
     invariant(!is_null($handle), ''); 
     $handle->succeed($ret); 
    } 
} 
Race::$handle = ConditionWaitHandle::create(
    \HH\Asio\v(
     Vector{ 
      (wait(1))->getWaitHandle(), 
      (wait(1000000))->getWaitHandle() 
     } 
    ) 
); 
printf("%d microsecond `wait` wins!", \HH\Asio\join(Race::$handle)); 

Sehr elegante Lösung, dank @jano!

* (der Schein zu Versprechen/latente verstärkt)


Ich bin neugierig, wie eine vorzeitige Beendigung über ConditionWaitHandle kämmt mit der Philosophie, dass all Awaitables should run to completion.

Verwandte Themen