Skip to content

Instantly share code, notes, and snippets.

@jordillonch
Created March 29, 2014 22:42
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jordillonch/9864239 to your computer and use it in GitHub Desktop.
Save jordillonch/9864239 to your computer and use it in GitHub Desktop.
HHVM async example using curl_multi_exec
<?hh
// Based on https://gist.github.com/chregu/9740519
class Fetcher {
// async function: http://docs.hhvm.com/manual/en/hack.async.php
// return type annotation: http://docs.hhvm.com/manual/en/hack.annotations.introexample.php
// generics: http://docs.hhvm.com/manual/en/hack.generics.php
public async function fetch(string $url) : Awaitable<array>
{
$ch1 = curl_init();
print "get $url \n";
curl_setopt($ch1, CURLOPT_URL, $url);
curl_setopt($ch1, CURLOPT_HEADER, 0);
curl_setopt($ch1, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch1, CURLOPT_FOLLOWLOCATION, true);
$mh = curl_multi_init();
curl_multi_add_handle($mh,$ch1);
$active = null;
do {
$mrc = curl_multi_exec($mh, $active);
// reschedule it for async to work properly
await RescheduleWaitHandle::Create(1, 1);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
while ($active && $mrc == CURLM_OK) {
if (curl_multi_select($mh) != -1) {
do {
$mrc = curl_multi_exec($mh, $active);
await RescheduleWaitHandle::Create(1, 1); // simulate blocking I/O
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
}
}
$content = curl_multi_getcontent($ch1);
print "finished $url\n";
// print $content;
return array(
'url' => $url,
'content'=> $content
);
}
}
class Fetch {
protected Fetcher $fetcher;
//Constructor Argument Promotion http://docs.hhvm.com/manual/en/hack.constructorargumentpromotion.php
//Vector http://docs.hhvm.com/manual/en/hack.collections.vector.php (instead of array)
//Annotating Arrays and Collections: http://docs.hhvm.com/manual/en/hack.annotations.arrays.php
public function __construct(private Vector<string> $urls)
{
$this->fetcher = new Fetcher();
}
public async function run() : Awaitable<array>
{
//lambda expressions: http://docs.hhvm.com/manual/en/hack.lambda.php
$waithandles = $this->urls->map(function($url) {
return $this->fetcher->fetch($url);
});
// works too, but not supported by typechecker yet
//$waithandles = $this->urls->map((string $url): Awaitable<int> ==> $this->fetcher->fetch($url));
// same as above, but with closure and annotations, so it catches type errors
//$waithandles = $this->urls->map(function(string $url): Awaitable<int> {return $this->fetcher->fetch($url);});
//create wait handle for all and only continue when all have finished
$x = await GenVectorWaitHandle::Create($waithandles);
// print_r($x);
return $x;
}
public function start() : array
{
$x = $this->run()->join();
// print_r($x);
return $x;
}
}
function main() {
//Vector with Literal Syntax: http://docs.hhvm.com/manual/en/hack.collections.literalsyntax.php
$urls = Vector{'http://chregu.tv/webinc/sleep.php?s=1', 'http://chregu.tv/webinc/sleep.php?s=1', 'http://chregu.tv/webinc/sleep.php?s=1'};
$f = new Fetch($urls);
$dataFetched = $f->start();
$dataFetched->map(function($urlContent) {
print $urlContent['url'] . ' => ' . substr($urlContent['content'], 0, 120) . "...\n\n";
});
// print_r($dataFetched);
}
main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment