hiệu suất str trong python


88

Trong khi lập hồ sơ một đoạn mã python ( python 2.6tối đa 3.2), tôi đã phát hiện ra rằng strphương pháp chuyển đổi một đối tượng (trong trường hợp của tôi là số nguyên) thành một chuỗi gần như chậm hơn so với sử dụng định dạng chuỗi.

Đây là điểm chuẩn

>>> from timeit import Timer
>>> Timer('str(100000)').timeit()
0.3145311339386332
>>> Timer('"%s"%100000').timeit()
0.03803517023435887

Có ai biết tại sao lại như vậy không? Tui bỏ lỡ điều gì vậy?


2
Và những gì về'{}'.format(100000)
wim

Đó là chậm nhất nhưng cũng linh hoạt nhất.
Luca Sbardella

Câu trả lời:


106

'%s' % 100000 được đánh giá bởi trình biên dịch và tương đương với một hằng số tại thời điểm chạy.

>>> import dis
>>> dis.dis(lambda: str(100000))
  8           0 LOAD_GLOBAL              0 (str)
              3 LOAD_CONST               1 (100000)
              6 CALL_FUNCTION            1
              9 RETURN_VALUE        
>>> dis.dis(lambda: '%s' % 100000)
  9           0 LOAD_CONST               3 ('100000')
              3 RETURN_VALUE        

%với biểu thức thời gian chạy không nhanh hơn (đáng kể) so với str:

>>> Timer('str(x)', 'x=100').timeit()
0.25641703605651855
>>> Timer('"%s" % x', 'x=100').timeit()
0.2169809341430664

Xin lưu ý rằng strtốc độ vẫn chậm hơn một chút, như @DietrichEpp đã nói, điều này là do strliên quan đến thao tác tra cứu và gọi hàm, trong khi %biên dịch thành một mã bytecode duy nhất ngay lập tức:

>>> dis.dis(lambda x: str(x))
  9           0 LOAD_GLOBAL              0 (str)
              3 LOAD_FAST                0 (x)
              6 CALL_FUNCTION            1
              9 RETURN_VALUE        
>>> dis.dis(lambda x: '%s' % x)
 10           0 LOAD_CONST               1 ('%s')
              3 LOAD_FAST                0 (x)
              6 BINARY_MODULO       
              7 RETURN_VALUE        

Tất nhiên điều trên đúng với hệ thống tôi đã thử nghiệm (CPython 2.7); các triển khai khác có thể khác.


Quả thực đây là lý do, tôi vừa thử bản thân và định dạng chuỗi chỉ nhanh hơn khoảng 5% str. Cảm ơn về câu trả lời. Không có lý do gì để thay đổi mã ở mọi nơi :-)
Luca Sbardella

2
Nói rõ hơn: strlà một tên có thể được phục hồi thành một cái gì đó khác với kiểu chuỗi, nhưng định dạng chuỗi - tức là str.__mod__phương thức - không thể thay thế, cho phép trình biên dịch thực hiện việc tối ưu hóa. Trình biên dịch không làm rất nhiều trong cách tối ưu hóa, nhưng nó nhiều hơn bạn có thể nghĩ :)
Karl Knechtel

4
... và bài học rút ra ở đây là: đừng bao giờ sử dụng các chữ trong các bài kiểm tra như thế này!
UncleZeiv

Mục nhập blog cụ thể này có thể bạn quan tâm: skymind.com/~ocrow/python_string . Nó chứa một biểu đồ các điểm chuẩn cho các phương pháp nối chuỗi khác nhau tương tự như những gì bạn đã cung cấp ở trên.
Aaron Newton

14

Một lý do được nghĩ đến là thực tế str(100000)liên quan đến tra cứu toàn cầu, nhưng "%s"%100000không. Toàn strcầu phải được tra cứu trong phạm vi toàn cầu. Điều này không tính đến toàn bộ sự khác biệt:

>>> Timer('str(100000)').timeit()
0.2941889762878418
>>> Timer('x(100000)', 'x=str').timeit()
0.24904918670654297

Theo ghi nhận của thg435 ,

>>> Timer('"%s"%100000',).timeit()
0.034214019775390625
>>> Timer('"%s"%x','x=100000').timeit()
0.2940788269042969
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.