2016-12-30 9 views
1

Я пытаюсь реализовать Rx-поток/наблюдаемое слияние с Hack async, а основной шаг описывается заголовком. Версия кода этого шага будет выглядеть примерно так:Преобразование коллекции Awaitables в упорядоченный по времени AsyncGenerator в 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 
    } 
} 

Однако, после обдумывает над этим, я не думаю, что может написать снимавшийся (**) функцию. Я обнаружил, что в какой-то момент реализации, которые я пробовал, требуют функциональности, сходной с JS, которая разрешает, когда первая из коллекции Promises разрешает/отклоняет. Тем не менее, все Hack's Awaitable collection helpers создать Ожидаемый полностью решена коллекция. Кроме того, Hack не позволяет нам звонить await с async function с, что также оказалось необходимым.

Возможно ли кому-нибудь знать?

ответ

0

Это возможно на самом деле! Я выкопал и наткнулся на a fork of asio-utilities от @jano, внедряя класс AsyncPoll. See PR for usage. Он делает то, что я надеялся.

Так что получается, есть Awaitable называется ConditionWaitHandle с succeed и fail методами *, которые могут быть вызваны любой контекст (so long as the underlying WaitHandle hasn't expired yet), вынудив ConditionWaitHandle разрешить с переданными значениями.

Я дал код жесткого взгляда, и под ним все работает, с помощью последовательных Awaitable гонок, которые разрешены ConditionWaitHandle. Более конкретно, сбор Awaitable s сжимается через AwaitAllWaitHandles (aka \HH\Asio\v), который разрешается так же медленно, как и самый медленный Awaitable, а затем вложен в ConditionWaitHandle. Каждый Awaitable ожидается в async function, который вызывает общий ConditionWaitHandle, заканчивая гонку. Это повторяется до тех пор, пока все решения не будут устранены.

Вот более компактная реализация гонки с использованием той же философии:

<?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)); 

Очень элегантное решение, благодаря @jano!

* (подобие обещания/отсроченных усиливается)


Мне любопытно, как преждевременное завершение через ConditionWaitHandle сцепляется с философией, что all Awaitables should run to completion.