PHP Profi

Асинхронный параллельный запуск кода в PHP на примере Laravel Collection Перевод

Фреймворк Laravel имеет отличный класс для работы с коллекциями, который имеет много полезных операций. Класс также является macroable. Это означает, что к нему можно добавлять функции во время выполнения путем вызова его метода macro и передачи названия и замыкания. В наших проектах мы, как правило, пишем один и тот же макрос снова и снова. Вот почему мы вынесли эти макросы в пакет laravel-collection-macros, так что вы можете их использовать, котоый основан на amphp/parallel.

В этом посте я хотел бы поговорить немного о новом макросе,  называемом parallelMap. parallelmap идентична map`у, но каждый элемент в коллекции будут обрабатываться параллельно.

Давайте взглянем на пример:

$pageSources = collect($urls)->parallelMap(function($url) {
    return file_get_contents($url);
});

Содержимое данных $urls будет получено одновременно. Это будет гораздо быстрее, чем последовательное извлечение содержимого для каждого URL-адреса. Классная штука!

Вот еще один кусок кода, взятый из наших тестов:

/** @test */
public function it_can_perform_async_map_operations()
{
    $this->startStopWatch();

    $collection = Collection::make([1, 2, 3, 4, 5])->parallelMap(function (int $number) {
        sleep(1);

        return $number * 10;
    });

    $this->assertTookLessThanSeconds(2);

    $this->assertEquals([10, 20, 30, 40, 50], $collection->toArray());
}

Вам, наверное, интересно, как эта магия работает. Ну, самое трудное внутри нового пакета  Amp's parallel-functions. Вот краткое описание того, что это взято из их документации:

amphp/parallel-functions - это упрощенный слой над amphp/parallel. Он позволяет параллельное выполнение кода за счет использования потоков или процессов, в зависимости от установленных расширений. Все данные, отправленные / полученные от дочерних процессов / потоков, должны быть сериализуемыми с использованием функцию РНР  serialize().

Вот пример, опять же взятый из их документации, о том, как можно использовать пакет напрямую:

use Amp\Promise;
use function Amp\ParallelFunctions\parallelMap;

$values = Promise\wait(parallelMap([1, 2, 3], function ($time) {
    \sleep($time); // a blocking function call, might also do blocking I/O here

    return $time * $time;
}));

 ParallelMap macro в нашем пакете просто использует свою магию. Вот определение macro:

Collection::macro('parallelMap', function (callable $callback): Collection {
    $promises = parallelMap($this->items, $callback);

    $this->items = wait($promises);

    return $this;
});

Помните, что вы не должны использовать parallelMap, если можно очень просто выполнить ту же самую работу через closure. Использование parallelMap это достаточно большой overhead. Не используйте его для небольших операций или для больших коллекцию.

Спасибо Никлас Келлер за Amp и за замечательный amphp/parallel-functions

2017-12-25 оригинал

Последние посты

Комментарии

авторизуйтесь или зарегистрируйтесь, чтобы оставить комментарий