Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Is it possible to make first class callables faster? #16759

Closed
adataxtra opened this issue Nov 11, 2024 · 4 comments
Closed

Is it possible to make first class callables faster? #16759

adataxtra opened this issue Nov 11, 2024 · 4 comments

Comments

@adataxtra
Copy link

Description

First class callables feel like the right way to do callbacks since you get propper completion from from your IDE/editor but the performance hit is rather bad. I'm sadly not very familiar with C or PHP internals but would it be possible for opcache to get performance parity with the "string" version of the callbacks? Maybe not for userland functions but at least for internal functions.

<?php

$a = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'];

$s = microtime(true);

for ($i = 0; $i < 100_000; $i++) {
    $u = array_map(strtoupper(...), $a);
}

echo (microtime(true) - $s) . PHP_EOL;

$s = microtime(true);

for ($i = 0; $i < 100_000; $i++) {
    $u = array_map('strtoupper', $a);
}

echo (microtime(true) - $s) . PHP_EOL;

$s = microtime(true);

for ($i = 0; $i < 100_000; $i++) {
    $u = array_map(fn($v) => strtoupper($v), $a);
}

echo (microtime(true) - $s) . PHP_EOL;

3v4l.org with PHP 8.3.13

0.061099052429199
0.026753902435303
0.043981075286865

3v4l.org with git.master

0.051828861236572
0.030702114105225
0.04832911491394
@nielsdos
Copy link
Member

Part of the reason of this is definitely the fact you're recreating a callable object over and over in the loop. If you bring strtoupper(...) out of the loop and assign it a variable, it gets pretty close to the string case.

@adataxtra
Copy link
Author

Oh yeah, I didn't think about that. It helped a bit but it is still a lot slower.

<?php

$a = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'];

$s = microtime(true);

$f = strtoupper(...);

for($i = 0; $i < 100_000; $i++) {
    $u = array_map($f, $a);
}

echo (microtime(true) - $s) . PHP_EOL;

$s = microtime(true);

for($i = 0; $i < 100_000; $i++) {
    $u = array_map('strtoupper', $a);
}

echo (microtime(true) - $s) . PHP_EOL;

$s = microtime(true);

$f = fn($v) => strtoupper($v);

for($i = 0; $i < 100_000; $i++) {
    $u = array_map($f, $a);
}

echo (microtime(true) - $s) . PHP_EOL;
0.055514097213745
0.027177095413208
0.038023948669434

@nielsdos
Copy link
Member

I get very different results on a release compile of 8.4-dev:

0.04678201675415
0.043025016784668
0.056145906448364

FWIW I tried this on 8.3 too:

0.045254945755005
0.043359041213989
0.054478883743286

So pretty much the same.
Are you only testing on 3v4l or also locally? Any noise in the background that may influence the results? Also try changing the order of the loops to rule out noise.

@adataxtra
Copy link
Author

I just updated to PHP 8.3.13 locally and yes it is much closer now. I guess I'll close the issue :)

Defined outside of the loop:

0.023478984832764
0.020103931427002
0.032291889190674

Defined in the loop:

0.028333187103271
0.020879030227661
0.033040046691895

@cmb69 cmb69 closed this as not planned Won't fix, can't repro, duplicate, stale Nov 13, 2024
# for free to join this conversation on GitHub. Already have an account? # to comment
Projects
None yet
Development

No branches or pull requests

3 participants