2011-11-19 36 views
7

Đây là một sự tối ưu hóa vi mô khá tệ, nhưng tôi chỉ tò mò. Nó thường không tạo nên sự khác biệt trong thế giới "thực".Tại sao cuộc gọi hàm trống trong python chậm hơn khoảng 15% đối với mã python được biên dịch động

Vì vậy, tôi đang biên soạn một hàm (không có gì) bằng cách sử dụng compile() rồi gọi exec trên mã đó và nhận tham chiếu đến hàm tôi đã biên dịch. Sau đó, tôi thực hiện nó một vài triệu lần và định thời gian. Sau đó lặp lại nó với một hàm cục bộ. Tại sao chức năng tự động biên dịch chậm hơn khoảng 15% (trên trăn 2.7.2) chỉ cho cuộc gọi?

import datetime 
def getCompiledFunc(): 
    cc = compile("def aa():pass", '<string>', 'exec') 
    dd = {} 
    exec cc in dd 
    return dd.get('aa') 

compiledFunc = getCompiledFunc() 
def localFunc():pass 


def testCall(f): 
    st = datetime.datetime.now() 
    for x in xrange(10000000): f() 
    et = datetime.datetime.now() 
    return (et-st).total_seconds() 

for x in xrange(10): 
    lt = testCall(localFunc) 
    ct = testCall(compiledFunc) 
    print "%s %s %s%% slower" % (lt, ct, int(100.0*(ct-lt)/lt)) 

Kết quả tôi nhận được là một cái gì đó như:

1.139 1.319 15% slower 
+0

chuyển ngữ cảnh? I E. khi bạn gọi hàm được biên dịch, bạn vẫn đang đi vào một phạm vi mới, thực hiện hàm và trả về kết quả từ phạm vi? (Tôi không phải là chuyên gia về python, chỉ cần đoán) –

+6

Các phép đo của bạn bị tắt. Sử dụng 'timeit' để lấy các số đo không thiên vị, và kết quả sẽ giống nhau (tôi đã thử, chúng là). Hai đối tượng hàm không thể phân biệt được và chúng có mã byte giống nhau. –

+1

@SvenMarnach Trả lời với microbenchmark truy cập? –

Trả lời

11

Các dis.dis() chức năng cho thấy rằng đối tượng mã cho mỗi phiên bản là giống hệt nhau:

aa 
    1   0 LOAD_CONST    0 (None) 
       3 RETURN_VALUE   
localFunc 
10   0 LOAD_CONST    0 (None) 
       3 RETURN_VALUE 

Vì vậy, sự khác biệt nằm trong đối tượng hàm. Tôi so sánh từng lĩnh vực (func_doc, func_closure, vv) và một trường khác với func_globals. Nói cách khác, localFunc.func_globals != compiledFunc.func_globals.

Có một chi phí để cung cấp từ điển của riêng bạn thay vì các hình cầu tích hợp (trước đây phải được tra cứu khi khung ngăn xếp được tạo trên mỗi cuộc gọi và thứ hai có thể được tham chiếu trực tiếp bằng mã C biết về từ điển nội dung dựng sẵn mặc định).

này được dễ dàng kiểm tra bằng cách thay đổi exec dòng trong mã của bạn để:

exec cc in globals(), dd 

Với rằng thay đổi, sự khác biệt thời gian sẽ biến mất.

Bí ẩn được giải quyết!

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