Amp кооперативная многозадачность / асинхронный сон

В однопоточном PHP мне нужно написать приложение, которое:

  • а) функционировать как HTTP-сервер
  • б) в состоянии сделать несколько HTTP-запросов

а) и б) должны работать, даже когда сервер ожидает / обслуживает запрос или HTTP-клиент ожидает ответа

У меня возникла идея использовать сервер PHP Amp. Работает отлично.

Однако для HTTP-клиента мне нужно использовать PHP curl.

Мой код выглядит так:

...
$mh = curl_multi_init();
curl_multi_add_handle($mh, $ch);
do {
AmpLoopHelper::asyncSleep(0.001);
$mrc = curl_multi_exec($mh, $isRunning);
} while ($isRunning && ($mrc == CURLM_CALL_MULTI_PERFORM || $mrc == CURLM_OK));
...

и обычай AmpLoopHelper учебный класс:

<?php

namespace Mvorisek\Dsv;

use Amp\Loop;
use Amp\Loop\Driver;


class AmpLoopHelper {
/** @var int|null */
private static $dummyWatcherId;

/**
* Async sleep and keep processing of Loop tasks.<br>
* Loop\Driver::tick() is always called at least once even if
* the sleep delay is zero or negative.
*
* @param float $sleepSecs
*/
public static function asyncSleep(float $sleepSecs): void {
$t = microtime(true);

// add dummy function to repeat to prevent Loop\Driver::tick() to block
$maxCheckDelayMillis = min(max(1, $sleepSecs * 1000 / 50), 50);
$isNested = static::$dummyWatcherId !== null;
if (!$isNested) {
static::$dummyWatcherId = Loop::repeat($maxCheckDelayMillis, static function() {});
}

try {
do {
if (static::loopDriverIsRunning()) {
static::loopDriverTick();
} else {
usleep(($sleepSecs - (microtime(true) - $t)) * 1e6);
break;
}
usleep(40);
} while(microtime(true) - $t < $sleepSecs);
} finally {
if (!$isNested) {
Loop::cancel(static::$dummyWatcherId);
}
}
}

private static function loopDriverGet(): Driver {
return \Closure::bind(static function() {
return Loop::$driver;
}, null, Loop::class)();
}

private static function loopDriverIsRunning(): bool {
$driver = static::loopDriverGet();
return \Closure::bind(static function() use($driver) {
return $driver->running;
}, null, Driver::class)();
}

private static function loopDriverTick(): void {
$driver = static::loopDriverGet();
\Closure::bind(static function() use($driver) {
$driver->tick();
}, null, Driver::class)();
}
}

Но HTTP-сервер иногда недоступен. Вспомогательный класс использует некоторые закрытые методы классов Amp.

Является ли идея asyncSleep правильный?

1

Решение

Проблема заключалась в том, что Driver->dispatch() может вызываться с флагом блокировки, и потоки блокировки не были обновлены из моего вспомогательного класса.

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]