1

Not sure why there isn't yet a "hack" tag (sorry to list in PHP), but...

I am wondering if it/how it would be possible to walk an array using multiple threads using the multithreaded/async feature of hack. I don't really need this, but it is a curiosity and might be useful.

I've looked at the documentation for "Hack"'s async feature

http://docs.hhvm.com/manual/en/hack.async.php

and its a bit difficult.

Here is the basic idea of what I would like to make (or see done):

a) Split up the array into x sections and process it on x "threads" or b) create x threads and each processes the latest available item, ie. when it the thread processes the item, it asks the parent thread for a new one to process. Hack doesn't do "threads", but the same is represented by an asyc function

Basically, the end goal is to quickly optimize a standard foreach block to run on multiple threads, so minimal code change is required, and also to see what hack can do and how it works.

I've come up with some code as a sample, but I think I've totally got the idea wrong.

class ArrayWalkAsync
{
    protected $array;
    protected $threads = Array();
    protected $current_index = 0;
    protected $max_index;
    protected $threads = 4;

    public function array_walk($array)
    {
        $this->array = $array;
        $this->max_index = count($array) - 1;
        $result = Array();
        for ($i=0;$i<$this->threads;$i++)
        {
            $this->threads[] = new ArrayWalkThread();
        }
        $continue = true;
        while($continue)
        {
            $awaitables = Array();
            for ($i=0;$i<$this->threads;$i++)
            {
                $a = $this->proccesNextItem($i);
                if ($a)
                {
                    $this->threads[] = $a;
                } else {
                    $continue = false;
                }
            }
            // wait for each
            foreach ($awaitables as $awaitable_i)
            {
                await awaitable_i;
                // do something with the result
            }
        }
    }

    protected function proccesNextItem($thread_id)
    {
        if ($this->current_index > $this->max_index)
        {
            return false;
        }
        $a = new ArrayWalkItem();
        $a->value = $this->array[$this->current_index];
        $a->index = $this->current_index;
        $this->current_index++;
        return $this->threads[$thread_id]->process($a,$this);
    }

    public function processArrayItem($item)
    {
        $value = $item->value;
        sleep(1);
        $item->result = 1;
    }

}


class ArrayWalkThread
{
     async function process($value,$parent): Awaitable<?ArrayWalkItem>
     {
        $parent->processArrayItem($a);
     }

}

class ArrayWalkItem
{
    public $value;
    public $result;
}
4

1 回答 1

3

Hack 的异步函数不会做你想做的事。在 Hack 中,异步函数不是线程。这是一种隐藏 IO 延迟和数据获取的机制,而不是一次执行多个计算。(这与 C# 中的相同,Hack 功能的来源。)

这篇关于异步函数的博文有一个很好的解释:

几个月来,Hack 提供了一个名为 async 的功能,它可以编写协同执行多任务的代码。这有点类似于线程,因为多个代码路径是并行执行的,但是它通过在任何给定时刻仅实际执行一个部分来避免多线程代码常见的锁争用问题。

“那有什么用?”,我听到你问。您仍然绑定到一个 CPU,因此执行代码应该花费相同的时间,对吧?嗯,这在技术上是正确的,但脚本代码执行并不是导致应用程序延迟的唯一原因。其中最大的一部分可能来自等待后端数据库响应查询。

[...]

当 [an http] 调用正忙于等待响应时,您没有理由不能做其他事情,甚至可能触发更多请求。数据库查询也是如此,它可能需要同样长的时间,甚至是比网络更快的文件系统访问,但仍然会引入几毫秒的延迟时间,所有这些都加起来!

很抱歉在这一点上造成混淆——你不是唯一一个试图以这种方式错误地使用异步的人。当前的文档在解释这一点方面做得很糟糕。我们正在修改文档;当前的草案做得更好一些,但我要提交一个任务,以确保在我们发布新文档之前它非常清晰。

于 2015-10-04T19:52:24.003 回答