2011-12-02 23 views
5

tôi muốn biết chính xác những gì sẽ xảy ra khi tôi sử dụng phản ánh để gọi một phương thức có tên tôi có như là một chuỗi:

my $foo = Foo->new(); 
my $method = 'myMethod'; 
$foo->$method(); 

là ~ Chậm hơn 20% so với gọi nội hạt:

$foo->myMethod(); 

Bất kỳ gợi ý nào về tài liệu về cách phản chiếu của perl được thực hiện sẽ hữu ích.

Cảm ơn.

+3

Tôi nghĩ rằng khá rõ ràng rằng thay vì mã op chứa tham chiếu đến một phương thức cụ thể, nó cần thêm hướng dẫn để tra cứu phương thức trong chuỗi ký hiệu của hệ thống phân cấp '@ ISA' và gửi đến thời gian chạy. – Axeman

+1

@Axeman, phương thức công văn là động - xem xét thời gian chạy '@ ISA' (hoặc bảng biểu tượng) sửa đổi, các đối tượng' bless'ing lại, v.v. Ngoài ra, ['perlobj'] (http://perldoc.perl.org/ perlobj.html) mô tả phương pháp tra cứu như thời gian chạy-lưu trữ, mà lúc đầu đỏ mặt cho thấy rằng thăm dò '@ ISA' không thể tài khoản cho sự khác biệt tốc độ. – pilcrow

Trả lời

4

Trước tiên, tôi không tin tưởng điểm chuẩn mà tôi không thấy. Nó quá dễ dàng để làm cho họ sai. Tôi đã tự chuẩn bị chúng.

use strict; 
use warnings; 

use Benchmark qw(cmpthese); 

sub new { return bless({}, $_[0]); } 
sub myMethod { } 

my %tests = (
    rt => '$foo->$method() for 1..1000;', 
    ct => '$foo->myMethod() for 1..1000;', 
); 

$_ = 'use strict; use warnings; our $foo; our $method; ' . $_ 
    for values(%tests); 

our $foo = __PACKAGE__->new(); 
our $method = 'myMethod'; 

cmpthese(-3, \%tests); 

Tôi có thể nhân rộng kết quả của bạn.

 Rate rt ct 
rt 1879/s -- -19% 
ct 2333/s 24% -- 

(Rate is 1/1000th of actual rate.) 

Điều đó có vẻ khá lớn, nhưng tỷ lệ phần trăm có thể rất gây nhầm lẫn với nội dung quá nhanh. Hãy nhìn vào sự khác biệt về thời gian tuyệt đối.

Compile-time: 2333000 calls per second = 429 nanoseconds per call 
Run-time:  1879000 calls per second = 532 nanoseconds per call 
Difference: 103 nanoseconds per call. 

Không nhiều. Vậy thời gian đó dành cho đâu?

$ perl -MO=Concise,-exec -e'$foo->myMethod()'  $ perl -MO=Concise,-exec -e'$foo->$method()' 
1 <0> enter         = 1 <0> enter 
2 <;> nextstate(main 1 -e:1) v:{    = 2 <;> nextstate(main 1 -e:1) v:{ 
3 <0> pushmark s        = 3 <0> pushmark s 
4 <#> gvsv[*foo] s       = 4 <#> gvsv[*foo] s 
               + 5 <#> gvsv[*method] s 
5 <$> method_named[PV "myMethod"]    ! 6 <1> method K/1 
6 <1> entersub[t2] vKS/TARG     = 7 <1> entersub[t3] vKS/TARG 
7 <@> leave[1 ref] vKP/REFC     = 8 <@> leave[1 ref] vKP/REFC 
-e syntax OK         = -e syntax OK 

Có vẻ như khác biệt duy nhất là tìm kiếm bảng biểu tượng bổ sung. 100ns có vẻ quá nhiều cho điều đó. Nhưng để chắc chắn, hãy so sánh với cái gì đó nhỏ bé, nói như thêm một cái.

$ perl -MO=Concise,-exec -e'my $y = $x;'  $ perl -MO=Concise,-exec -e'my $y = $x + 1;' 
1 <0> enter        = 1 <0> enter 
2 <;> nextstate(main 1 -e:1) v:{   = 2 <;> nextstate(main 1 -e:1) v:{ 
3 <#> gvsv[*x] s       = 3 <#> gvsv[*x] s 
              + 4 <$> const[IV 1] s 
              + 5 <2> add[t3] sK/2 
4 <0> padsv[$y:1,2] sRM*/LVINTRO   = 6 <0> padsv[$y:1,2] sRM*/LVINTRO 
5 <2> sassign vKS/2      = 7 <2> sassign vKS/2 
6 <@> leave[1 ref] vKP/REFC    = 8 <@> leave[1 ref] vKP/REFC 
-e syntax OK        = -e syntax OK 

Cắm rằng mã và our $x = 100; vào mã chuẩn trên, chúng tôi nhận

  Rate addition baseline 
addition 4839/s  --  -26% 
baseline 6532/s  35%  -- 

(Rate is 1/1000th of actual rate.) 

Vì vậy,

Basline: 6553000/s = 153 nanoseconds per assignment 
Addition: 4839000/s = 207 nanoseconds per assignment+addition 
Difference:    54 nanoseconds per addition 

Vậy là nó hợp lý cho một tra cứu bảng biểu tượng đơn giản để chăm gấp đôi miễn là thêm một? Có lẽ, kể từ khi nó liên quan đến băm một chuỗi và tìm kiếm một chuỗi trong danh sách liên kết ngắn.

Bạn có thực sự quan tâm đến việc chi tiêu thêm 100ns ở đây và ở đó không? Không, tôi đoán vậy.

+0

+1 cho một "tối ưu hóa sớm"! :-) – Tanktalus

10
> perl -MO=Concise -e '$foo->$bar' 
8 <@> leave[1 ref] vKP/REFC ->(end) 
1  <0> enter ->2 
2  <;> nextstate(main 1 -e:1) v:{ ->3 
7  <1> entersub[t3] vKS/TARG ->8 
3  <0> pushmark s ->4 
-  <1> ex-rv2sv sKM/1 ->5 
4   <#> gvsv[*foo] s ->5 
6  <1> method K/1 ->7    # ops to read $bar and then call method 
-   <1> ex-rv2sv sK/1 ->6  # 
5    <#> gvsv[*bar] s ->6  # 
-e syntax OK 

> perl -MO=Concise -e '$foo->bar' 
7 <@> leave[1 ref] vKP/REFC ->(end) 
1  <0> enter ->2 
2  <;> nextstate(main 1 -e:1) v:{ ->3 
6  <1> entersub[t2] vKS/TARG ->7 
3  <0> pushmark s ->4 
-  <1> ex-rv2sv sKM/1 ->5 
4   <#> gvsv[*foo] s ->5 
5  <$> method_named[PV "bar"] ->6 # op to call the 'bar' method 
-e syntax OK 

Trong ví dụ đầu tiên, perl có để tải biến $bar, và sau đó kiểm tra để xem nếu nó chứa một tên hoặc giá trị có thể được sử dụng như một phương pháp. Vì nội dung của $bar có thể thay đổi giữa các cuộc gọi, việc tra cứu này phải được thực hiện mỗi lần.

Trong ví dụ thứ hai, perl đã biết rằng chuỗi "bar" nên được sử dụng làm tên phương thức, do đó, tránh tải biến và kiểm tra nội dung của biến trên mỗi lần thực thi.

Nhưng bạn không nên lo lắng quá nhiều về chênh lệch tốc độ 20% giữa hai hoạt động gốc. Chủ yếu là do các hoạt động gốc rất nhanh, và bất kỳ tốc độ nào mà chúng thực sự yêu cầu sẽ nhanh chóng bị lùn bởi thuật toán thực tế mà mã của bạn phải thực hiện. Nói cách khác, trừ khi bạn đã bị cô lập vấn đề này như là một điểm nóng với một profiler mã, sự khác biệt tốc độ có nhiều sư phạm hơn tầm quan trọng thực tế.

1

Bạn có thể tăng tốc độ này lên bằng cách sử dụng một tài liệu tham khảo phương pháp, ala:

$metref = \&{"Class::$method"}; 
$instance = new Class; 
$instance->$metref(@args); 

Bạn rõ ràng là có thể sử dụng $metref = \&Class::myMethod thay vì nếu bạn biết tên phương pháp tại thời gian biên dịch. Ngoài ra còn có các bao đóng bằng cách sử dụng sub { ... } mà perl có thể xử lý hiệu quả hơn so với dereferencing biểu tượng của bạn. Xem this perlmonks discussionperlref : Making References.

+5

Tốt hơn để viết 'Class :: -> can ($ method)' để có được coderef. Nó tôn trọng sự thừa kế và hoạt động nghiêm ngặt. Ngoài ra, '$ metref -> ($ instance, @args)' thậm chí còn nhanh hơn. –

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