2

我有一种情况,我有一个循环,将从文件中读取数据块,将这些数据块发送到休息 api,然后继续直到 EOF,但我希望它在循环内是异步的,所以,我不必等到 API 响应读取下一个块。我一直在研究 Amphp 和 ReactPHP,因为我找不到解决方案,或者我不明白应该如何使用这些库。这是我正在做的伪。

<?php

while($file.read()){

   $chunk = getNextChunk();

   sendChunkAsync($chunk);

}

function getNextChunk(){

   echo "reading next chunk";

   // read next chunk of data

}

带有 amphp 的示例

function sendChunkAsync($chunk){

Loop::run(function () {

    $uri =  "https://testapi.com/api";

    $client = new DefaultClient;

    try {

            $promises = $client->request($uri);


        $responses = yield $promises;

       echo "chunk processed";

    } catch (Amp\Artax\HttpException $error) {

        // log error

        // $error->getMessage() . PHP_EOL;
    }
});

}

在这种情况下,我希望(如果读取块比从 api 获得响应更快)是这样的,不要拿这个文学作品,我试图为你说明它。

读取下一个块

读取下一个块

已处理的块

读取下一个块

已处理的块

已处理的块

4

2 回答 2

1

如果其他人试图解决类似的问题

<?php

require_once __DIR__ . '/../vendor/autoload.php';

use React\HttpClient\Client as ReactClient;

function async_send($loop, $filePath, callable $proccessor)
{
    echo "starting";
    echo "\n\r";

    try {

        $filesystem = \React\Filesystem\Filesystem::create($loop);

        $file = $filesystem->file($filePath);
        $file->open('r')
            ->then(function ($stream) use ($loop, $proccessor){
                $stream->on('data', function ($chunk) use ($loop, $proccessor) {
                   $proccessor($chunk);
                });
            });

    } catch (\Exception $e) {
        echo "failed";
        echo "\n\r";
    }
    echo "ending reading";
    echo "\n\r";
}

function callApiReal($loop, $fileChunk = null)
{
    echo "ready to call api". PHP_EOL;

    $uri = "https://testapi.com/";
    try {
        $client = new ReactClient($loop);
    } catch (\Exception $e) {
        echo "Error";
    }
    echo "ready to call api";

    $request = $client->request('POST', $uri, $fileChunk);

    $request->on('response', function ($response) use ($uri) {

        $response->on('data', function ($data_chunk) {
            echo 'data chunk from api received';
            echo "\n\r";
        });

        // subscribe to listen to the end of the response
        $response->on('end', function () use ($uri) {
            echo "operation has completed";
            echo "\n\r";
        });
    });

    $request->on('error', function ($error) {
        // something went bad in the request
        echo "Damm!";
        echo "\n\r";
    });

    $request->end();

}

// main loop
$loop = React\EventLoop\Factory::create();

//somewhere later
async_send($loop, __DIR__ . '/my.csv', function ($chunk) use ($loop) {
    echo "calling api";
    callApiReal($loop, $chunk);
    echo "\n\r";
});

$loop->run();
于 2018-12-06T22:09:15.550 回答
1

我将使用 React,因为我更了解这个库,但它们的工作方式相似。

编辑:更新,见评论

这将读入一个文件,每次它收到一大块数据时,它都会创建一个 api 调用并将数据发送出去

<?php

require_once __DIR__ . '/vendor/autoload.php';

function async_send($config, $file, callable $proccessor)
{

    $config['ssl'] = true === $config['ssl'] ? 's' : '';
    $client = new \GuzzleHttp\Client([
        'base_uri' => 'http' . $config['ssl'] . '://' . $config['domain'] . '/rest/all/V1/',
        'verify' => false,
        'http_errors' => false
    ]);
    $loop = \React\EventLoop\Factory::create();
    $filesystem = \React\Filesystem\Filesystem::create($loop);
    $filesystem->getContents($file)->then(function($contents) use ($config, $proccessor, $client) {
        $contents = $proccessor($contents);
        $client->post($config['uri'], ['body' => $contents]);
    });
}

$config = [
    'domain' => 'example.com',
    'ssl' => true
];
//somewhere later
$configp['uri'] = 'products';
async_send($configp, __DIR__ . 'my.csv', function ($contents) {
    return json_encode($contents);
});
于 2018-12-04T18:34:34.853 回答