【问题标题】:Converting a collection of Awaitables to a time-ordered AsyncGenerator in Hack在 Hack 中将 Awaitables 集合转换为按时间排序的 AsyncGenerator
【发布时间】:2017-05-15 04:56:10
【问题描述】:

我正在尝试使用 Hack async 实现 Rx 流/可观察合并,并且标题描述了一个核心步骤。此步骤的代码版本如下所示:

<?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 的 Promise.race 的功能,它在集合 Promises 中的第一个解决/拒绝时解决。然而,所有Hack's Awaitable collection helpers 都创建了一个完全 解析集合的Awaitable。此外,Hack 不允许我们不使用来自 async functions 的 await 异步调用,我也发现这是必要的。

有人知道吗?

【问题讨论】:

    标签: asynchronous async-await generator hacklang


    【解决方案1】:

    这实际上是可能的!我四处挖掘并通过@jano 实现AsyncPoll 类偶然发现a fork of asio-utilitiesSee PR for usage. 果然如我所愿。

    事实证明,有一个名为 ConditionWaitHandleAwaitable 带有 succeedfail 方法*,可以由任何上下文 (so long as the underlying WaitHandle hasn't expired yet) 调用,从而强制 ConditionWaitHandle 使用传递的值。

    我仔细查看了代码,在这一切之下,它通过连续的Awaitable 比赛来工作,ConditionWaitHandle 允许。更具体地说,Awaitables 的集合是通过AwaitAllWaitHandles(又名\HH\Asio\v)压缩的,它的解析速度与最慢的Awaitable 一样慢,然后嵌套在ConditionWaitHandle 中。每个Awaitable 都在async function 中等待,该async function 触发公共ConditionWaitHandle,结束比赛。重复此操作,直到 Awaitables 全部解决。

    这是使用相同理念的更紧凑的比赛实现:

    <?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!

    *(与 promises/deferred 的相似度增强)


    我很好奇通过ConditionWaitHandle 的过早完成与all Awaitables should run to completion 的理念如何相吻合。

    【讨论】:

      猜你喜欢
      • 2016-07-14
      • 1970-01-01
      • 1970-01-01
      • 2014-11-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-05
      相关资源
      最近更新 更多