2015-01-06 12 views
7

Tôi đang xem các ví dụ được đề cập here và đang xem this example. Tôi chạy một ví dụ mẫu dưới đây về ipython, và kết quả là phù hợp, ví dụ, "%d" là chậm hơn so với "%s":Tại sao% s nhanh hơn% d để thay thế số nguyên trong python?

In [1]: def m1(): 
    ...:  return "%d" % (2*3/5) 

In [2]: def m2(): 
    ...:  return "%s" % (2*3/5) 

In [4]: %timeit m1() 
1000000 loops, best of 3: 529 ns per loop 

In [5]: %timeit m2() 
1000000 loops, best of 3: 192 ns per loop 

In [6]: from dis import dis 

In [7]: dis(m1) 
    2   0 LOAD_CONST    1 ('%d') 
       3 LOAD_CONST    5 (6) 
       6 LOAD_CONST    4 (5) 
       9 BINARY_DIVIDE  
      10 BINARY_MODULO  
      11 RETURN_VALUE   

In [9]: dis(m2) 
    2   0 LOAD_CONST    1 ('%s') 
       3 LOAD_CONST    5 (6) 
       6 LOAD_CONST    4 (5) 
       9 BINARY_DIVIDE  
      10 BINARY_MODULO  
      11 RETURN_VALUE   

Cả khối mã tương tự, và thậm chí cả đầu ra của bộ phận phân tách là giống nhau, vậy tại sao là "%s" nhanh hơn "%d"?

+0

Nó rõ ràng là việc thực hiện quá tải BINARY_MODULO, không phải là bất kỳ lời giải thích ;-) Không liên quan .. khi nào Python bắt đầu làm việc gấp liên tục ('2 * 3')? – thebjorn

+0

Tôi không chắc tại sao sự khác biệt lại ở đó, nhưng điều làm cho sự khác biệt về thời gian không xảy ra bên trong mã byte bytecode, nhưng trong việc thực hiện toán tử modulo, điều này có thể xảy ra trong C. Nếu tôi không lầm tại sao nó không hiển thị trong quá trình tháo gỡ. – bigblind

+2

Chỉ cần lưu ý: sự khác biệt giữa hai xảy ra bên trong toán tử mô đun, vì vậy nó sẽ không xuất hiện trong bytecode của hàm sử dụng toán tử đó. – BrenBarn

Trả lời

5

này đã được thảo luận trong hacker news, tôi chỉ định dạng câu trả lời @nikital cho SO:

Chức năng PyString_Format trong Objects/stringobject.c hiện các định dạng cho các nhà điều hành %. Đối với %s, cuộc gọi đó gọi số _PyObject_Str mà lần lượt gọi str() trên đối tượng. Đối với %d, nó gọi số formatint (nằm trong cùng một tệp).

Việc thực hiện str() cho ints là trong int_to_decimal_string trong (Objects/intobject.c) và nó vô cùng đơn giản:

do { 
    *--p = '0' + (char)(absn % 10); 
    absn /= 10; 
} while (absn); 

Mã cho formatint là cách phức tạp hơn, và nó bao gồm hai cuộc gọi đến snprintf mẹ đẻ:

PyOS_snprintf(fmt, sizeof(fmt), "%s%%%s.%dl%c", 
       sign, (flags&F_ALT) ? "#" : "", 
       prec, type); 
// ... 
PyOS_snprintf(buf, buflen, fmt, -x); 

Bản gốc snprintf nặng hơn vì nó xử lý độ chính xác, không đệm và các nội dung tương tự.

Tôi tin rằng đây là lý do tại sao %d chậm hơn. %s là vòng lặp "chia-by-10 và trừ" thẳng trong khi %d là hai cuộc gọi thư viện đến số sprintf toàn diện. Tuy nhiên tôi đã không thực sự hồ sơ mã vì tôi không có một xây dựng gỡ lỗi, vì vậy tôi có thể hoàn toàn sai.

+0

Ahhhh! Tôi tìm thấy các liên kết cho các trang web trong bản tin tin tức của hacker ngày hôm nay, nên đã nhìn vào các diễn đàn là tốt. Dù sao, cảm ơn và +1. –

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