Hack: Asynchronous programming

2 minute read

Hack has introduced asynchronous programming. This is really great but it is not really documented at the moment. Not at all actually… I’ve done some experimenting and I will try to introduce you to the new concept.

There is two new keywords async and await. Async is used to declare a function as asynchronous. You need to declare the function with async if you want to run it in parallel with other functions. Every async function will return an Awaitable.

function foo(int $a): int {
//This will return a Awaitable.
$asyncCall = bar();


//The bar function may not have finished executing
if (!$asyncCall->isFinished()) {
echo "bar has not finished executing...\n";
}


//Wait for bar to finish and join the threads
$bar=$asyncCall->join();


return $bar+$a;
}


async function bar(): Awaitable<int> {
echo "bar started\n";


//sleep for one sec. Make sure we sleep async
//This could also be a remote API call...
await SleepWaitHandle::create(1 * 1000000);


echo "bar is done\n";


return 3;
}


echo "Result: ".foo(4);


//output
bar started
bar has not finished executing...
bar is done
Result: 7

Instead of the join function you may use the await keyword to suspend the execution of the async function waiting for the WaitHandle to complete.

There is also a series of object inheriting WaitHandle which you may us. Below is an example where you stack up asynchronous calls in a GenVectorWaitHandle and execute them all at once.

function main() : void
{
$info = Vector {};
for ($i = 0; $i < 5; $i++) {
$info[] = genInfo($i);
}


echo '[main] Calling Async Function'."\n";
$asyncCall = GenVectorWaitHandle::create($info);


echo '[main] Doing whatever...'."\n";


echo '[main] Time To Request Async Return Information'."\n";
$output = $asyncCall->join();


// Output Vector Data
foreach ($output as $key => $value)
{
echo '['.$key.'] => '.$value."\n";
}
}


async function genInfo(int $id): Awaitable<String> {
echo '[genInfo] Generating '.$id."\n";


$tmp = [];
$tmp['id'] = $id;
$tmp['start'] = date('H:i:s');


//do some heavy working.
await SleepWaitHandle::create(mt_rand(1000000,15*1000000));


$tmp['end'] = date('H:i:s');


echo "[genInfo] Completed $id\n";


return json_encode($tmp);
}


main();


/*
* This is a modified example from http://kernelcurry.com/blog/asynchronous-hack/
*/



//Output
[genInfo] Generating 0
[genInfo] Generating 1
[genInfo] Generating 2
[genInfo] Generating 3
[genInfo] Generating 4
[main] Calling Async Function
[main] Doing whatever...
[main] Time To Request Async Return Information
[genInfo] Completed 0
[genInfo] Completed 3
[genInfo] Completed 2
[genInfo] Completed 1
[genInfo] Completed 4
[0] => {"id":0,"start":"19:46:00","end":"19:46:03"}
[1] => {"id":1,"start":"19:46:00","end":"19:46:08"}
[2] => {"id":2,"start":"19:46:00","end":"19:46:05"}
[3] => {"id":3,"start":"19:46:00","end":"19:46:04"}
[4] => {"id":4,"start":"19:46:00","end":"19:46:08"}

Notice the last 5 lines in the output. The threads started at the very same time but completed at random order.

I think this feature need some more work before anyone should use it in production. We also need some more documentation on hacklang.org.

Categories:

Updated:

Leave a Comment