2010-06-05 27 views
12

Trong khi tối ưu hóa một hàm trong PHP, tôi đã thay đổiTại sao việc truyền và so sánh trong PHP nhanh hơn is_ *?

if(is_array($obj)) foreach($obj as $key=>$value { [snip] } 
else if(is_object($obj)) foreach($obj as $key=>$value { [snip] }

để

if($obj == (array) $obj) foreach($obj as $key=>$value { [snip] } 
else if($obj == (obj) $obj) foreach($obj as $key=>$value { [snip] }

Sau khi tìm hiểu về ===, tôi đã thay đổi đó để

if($obj === (array) $obj) foreach($obj as $key=>$value { [snip] } 
else if($obj === (obj) $obj) foreach($obj as $key=>$value { [snip] }

Thay đổi mỗi bài kiểm tra từ is_ * để đúc dẫn đến tăng tốc lớn (> 30%).

Tôi hiểu rằng === nhanh hơn == do không có sự ép buộc phải được thực hiện, nhưng tại sao lại truyền biến nhanh hơn rất nhiều so với việc gọi bất kỳ hàm nào là _ * -?

Edit: Kể từ khi mọi người hỏi về tính đúng đắn, tôi đã viết bài kiểm tra nhỏ này:

$foo=(object) array('bar'=>'foo'); 
$bar=array('bar'=>'foo'); 

if($foo===(array) $foo) echo '$foo is an array?'; 
if($bar===(object) $bar) echo '$bar is an object?'; 

Nó không in bất kỳ lỗi và cả hai biến không bị thay đổi, vì vậy tôi nghĩ rằng nó làm việc, nhưng tôi đã sẵn sàng để được thuyết phục bằng cách khác.

Một Edit: chương trình Artefacto của mang lại cho tôi những con số sau đây:

PHP 5.3.2-1ubuntu4.2 (64bit) on a Core i5-750 with Xdebug 
Elapsed (1): 0.46174287796021/0.28902506828308 
Elapsed (2): 0.52625703811646/0.3072669506073 
Elapsed (3): 0.57169318199158/0.12708187103271 
Elapsed (4): 0.51496887207031/0.30524897575378 
Speculation: Casting and comparing can be about 1.7-4 times faster.
PHP 5.3.2-1ubuntu4.2 (64bit) on a Core i5-750 without Xdebug 
Elapsed (1): 0.15818405151367/0.214271068573 
Elapsed (2): 0.1531388759613/0.25853085517883 
Elapsed (3): 0.16164898872375/0.074632883071899 
Elapsed (4): 0.14408397674561/0.25812387466431 
Without Xdebug, the extra function call didn't matter anymore, so every test (except 3) ran faster.
PHP 5.3.2-1ubuntu4.2 on a Pentium M 1.6GHz 
Elapsed (1): 0.97393798828125/0.9062979221344 
Elapsed (2): 0.39448714256287/0.86932587623596 
Elapsed (3): 0.44513893127441/0.23662400245667 
Elapsed (4): 0.38685202598572/0.82854390144348 
Speculation: Casting an array is slower, casting an object can be faster, but might not be slower.
PHP 5.2.6-1+lenny8 on a Xeon 5110 
Elapsed (1): 0.273758888245/0.530702114105 
Elapsed (2): 0.276469945908/0.605964899063 
Elapsed (3): 0.332523107529/0.137730836868 
Elapsed (4): 0.267735004425/0.556323766708 
Speculation: These results are similar to Artefacto's results, I think it's PHP 5.2. 

Giải pháp: Các hồ sơ tôi đã sử dụng (Xdebug) đã gọi chức năng khoảng 3 lần chậm hơn (ngay cả khi không định hình), nhưng không ảnh hưởng đến truyền và so sánh không đáng chú ý, do đó, đúc và so sánh xuất hiện để được nhanh hơn, mặc dù nó chỉ không bị ảnh hưởng bởi trình gỡ rối/profiler.

+4

Nếu tôi phải đoán, nó muốn được do tránh các chi phí của một cuộc gọi chức năng. – Amber

+2

Việc thay thế của bạn không dẫn đến một chương trình tương đương. Ví dụ, nếu '$ obj' là một đối tượng,' is_array ($ obj) 'trả về' false', nhưng có thể '($ obj == (array) $ obj)' đánh giá thành 'true'. – Artefacto

+0

@Artefacto có điều đó hoàn toàn đúng. Đó là những gì tôi cũng đã viết, xin vui lòng có một cái nhìn để trả lời của tôi, và cho tôi một số thông tin phản hồi – streetparade

Trả lời

4

Tôi thực sự không thể tái tạo. Trong thực tế, chiến lược của bạn mang lại cho tôi lần nữa trong tất cả ngoại trừ một trường hợp:

<?php 

class A { 
    private $a = 4; 
    private $b = 4; 
    private $f = 7; 
} 

$arr = array("a" => 4, "b" => 4, "f" => 7); 

$obj = new A(); 

$t = microtime(true); 

for ($i = 0; $i < 500000; $i++) { 
    is_array($obj) and die("err"); 
} 

echo "Elapsed (1.1): " . (microtime(true) - $t); 
echo "\n"; 

$t = microtime(true); 

for ($i = 0; $i < 500000; $i++) { 
    ($obj === (array) $obj) and die("err"); 
} 

echo "Elapsed (1.2): " . (microtime(true) - $t); 
echo "\n"; 

$t = microtime(true); 

for ($i = 0; $i < 500000; $i++) { 
    is_object($arr) and die("err"); 
} 

echo "Elapsed (2.1): " . (microtime(true) - $t); 
echo "\n"; 

$t = microtime(true); 

for ($i = 0; $i < 500000; $i++) { 
    ($arr === (object) $arr) and die("err"); 
} 

echo "Elapsed (2.2): " . (microtime(true) - $t); 
echo "\n"; 

$t = microtime(true); 

for ($i = 0; $i < 500000; $i++) { 
    is_object($obj) or die("err"); 
} 

echo "Elapsed (3.1): " . (microtime(true) - $t); 
echo "\n"; 

$t = microtime(true); 

for ($i = 0; $i < 500000; $i++) { 
    ($obj === (object) $obj) or die("err"); 
} 

echo "Elapsed (3.2): " . (microtime(true) - $t); 
echo "\n"; 

$t = microtime(true); 

for ($i = 0; $i < 500000; $i++) { 
    is_array($arr) or die("err"); 
} 

echo "Elapsed (4.1): " . (microtime(true) - $t); 
echo "\n"; 

$t = microtime(true); 

for ($i = 0; $i < 500000; $i++) { 
    ($arr === (array) $arr) or die("err"); 
} 

echo "Elapsed (4.2): " . (microtime(true) - $t); 

Output:

 
Elapsed (1.1): 0.366055965424 
Elapsed (1.2): 0.550662994385 
Elapsed (2.1): 0.337422132492 
Elapsed (2.2): 0.579686880112 
Elapsed (3.1): 0.402997970581 
Elapsed (3.2): 0.190818071365 
Elapsed (4.1): 0.332742214203 
Elapsed (4.2): 0.549873113632 

Dàn diễn viên và so sánh chỉ nhanh hơn để kiểm tra nếu một cái gì đó là một đối tượng đã. Đầu cơ sau: có lẽ vì việc kiểm tra nhận dạng đối tượng chỉ yêu cầu xác định xem các bảng xử lý và các xử lý đối tượng có giống nhau không, trong khi kiểm tra nhận dạng mảng yêu cầu, trong trường hợp xấu nhất, so sánh tất cả các giá trị.

+0

Xdebug đã nghiêng số của tôi, tôi thấy vấn đề khi tôi so sánh i5 với Xeon. Tôi chấp nhận câu trả lời của bạn, nhưng bạn có thể muốn thêm một lưu ý về phiên bản PHP và addons (trình gỡ lỗi, bộ nhớ cache opcode, vv) ảnh hưởng đến điểm chuẩn. – tstenner

+0

@tstenner Windows 7 64 bit và Athlon 64 3500+, Bản phát hành bản PHP 5.3.2 được biên dịch với VC6. Không có trình gỡ lỗi hoặc bộ nhớ cache opcode (không phải là một bộ nhớ cache opcode sẽ làm cho một sự khác biệt; thời gian đếm số liệu thống kê sau khi biên dịch kịch bản). – Artefacto

3
  1. Có thể là trong một số phiên bản PHP, cuộc gọi hàm nhất định sẽ mất nhiều thời gian hơn chuyển đổi.
  2. Trình gỡ lỗi/trình gỡ rối sẽ thay đổi đáng kể các mối quan hệ này vì chúng ghi đè các trình xử lý cuộc gọi chức năng, v.v. để chúng thay đổi thời gian gọi hàm.
  3. Nếu bạn đang tối ưu hóa những điều này, bạn đang tìm kiếm địa điểm sai. Nếu ứng dụng PHP của bạn làm điều gì đó không tầm thường, hiệu năng của nó hầu như không bao giờ cải thiện từ lợi thế micro giây mà bạn có thể đạt được từ việc cố gắng làm việc ngoài công cụ, và thậm chí nếu nó có thể sẽ biến mất với phiên bản PHP tiếp theo. . Ví dụ, 5.Động cơ 2 và 5,3 khác nhau bên trong, và phiên bản tiếp theo sẽ có nhiều sự khác biệt. Những khác biệt này thường không ảnh hưởng đến mã nhưng chúng sẽ làm cho tất cả các tối ưu hóa vi mô của bạn không liên quan.
  4. Việc chuyển đổi nội dung không phải là đối tượng/mảng thành đối tượng/mảng có thể chậm hơn khi kiểm tra nói chung vì nó sẽ phải tạo đối tượng/mảng mới.
+0

Một micro giây có thể không có vẻ nhiều, nhưng thử nghiệm này đã chiếm hơn một phần tư thời gian thực hiện của hàm. – tstenner

+0

4. cũng làm tôi ngạc nhiên, đó là lý do tại sao một câu hỏi được đặt ra;) Dù sao, câu trả lời hay. +1 – tstenner

3

Tôi chỉ muốn thêm rằng tính năng so sánh diễn xuất chỉ nhanh hơn đối với mảng/đối tượng nhỏ.

for ($i = 0; $i < 10000; $i ++) { 
    $arr[] = $i; 
} 

$t = microtime(true); 
for ($i = 0; $i < 5000; $i ++) { 
    is_array($arr); 
} 
echo "Elapsed: " . (microtime(true) - $t) . "\n"; 

$t = microtime(true); 
for ($i = 0; $i < 5000; $i ++) { 
    ($arr === (array)$arr); 
} 
echo "Elapsed: " . (microtime(true) - $t) . "\n"; 

Output:

Elapsed: 0.0487940311432 
Elapsed: 9.20055603981 
+0

Ví dụ tuyệt vời! – CoR

Các vấn đề liên quan