ประสิทธิภาพ str ใน python


88

ในขณะที่สร้างโปรไฟล์โค้ด python ( python 2.6มากถึง3.2) ฉันค้นพบว่า strวิธีการแปลงวัตถุ (ในกรณีของฉันคือจำนวนเต็ม) เป็นสตริงนั้นแทบจะเรียงลำดับขนาดได้ช้ากว่าการใช้การจัดรูปแบบสตริง

นี่คือเกณฑ์มาตรฐาน

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

ไม่มีใครรู้ว่าทำไมถึงเป็นเช่นนี้? ฉันพลาดอะไรไปรึเปล่า?


2
และสิ่งที่เกี่ยวกับ'{}'.format(100000)
wim

นั่นคือช้าที่สุด แต่ยังยืดหยุ่นที่สุด
Luca Sbardella

คำตอบ:


106

'%s' % 100000 ได้รับการประเมินโดยคอมไพลเลอร์และเทียบเท่ากับค่าคงที่ ณ รันไทม์

>>> 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        

%ด้วยนิพจน์รันไทม์ไม่ (อย่างมีนัยสำคัญ) เร็วกว่าstr:

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

โปรดทราบว่าstrยังช้ากว่าเล็กน้อยตามที่ @DietrichEpp กล่าวเนื่องจากstrเกี่ยวข้องกับการค้นหาและการเรียกใช้ฟังก์ชันในขณะที่%คอมไพล์เป็นรหัสไบต์เดียวทันที:

>>> 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        

แน่นอนข้างต้นเป็นจริงสำหรับระบบที่ฉันทดสอบ (CPython 2.7); การใช้งานอื่น ๆ อาจแตกต่างกัน


อันที่จริงมีลักษณะเช่นนี้เหตุผลที่ฉันพยายามตัวเองและการจัดรูปแบบสตริงเป็นเพียงประมาณ 5% strเร็วกว่า ขอบคุณสำหรับคำตอบ. ไม่มีเหตุผลที่จะเปลี่ยนรหัสทุกที่ :-)
Luca Sbardella

2
เพื่ออธิบายเพิ่มเติม: strเป็นชื่อที่สามารถตอบกลับไปยังสิ่งอื่นที่ไม่ใช่ประเภทสตริง แต่การจัดรูปแบบสตริง - เช่นstr.__mod__วิธีการ - ไม่สามารถแทนที่ได้ซึ่งอนุญาตให้คอมไพเลอร์ทำการเพิ่มประสิทธิภาพ คอมไพเลอร์ไม่ได้ทำอะไรมากในการเพิ่มประสิทธิภาพ แต่ทำได้มากกว่าที่คุณคิด :)
Karl Knechtel

4
... และบทเรียนที่ต้องเรียนรู้ที่นี่คืออย่าใช้ตัวอักษรในการทดสอบเช่นนี้!
UncleZeiv

รายการบล็อกนี้โดยเฉพาะคุณอาจจะสนใจ: skymind.com/~ocrow/python_string ประกอบด้วยแผนภูมิของการวัดประสิทธิภาพสำหรับวิธีการต่อสายอักขระต่างๆที่คล้ายกับที่คุณระบุไว้ข้างต้น
Aaron Newton

14

เหตุผลหนึ่งที่อยู่ในใจคือความจริงที่str(100000)เกี่ยวข้องกับการค้นหาทั่วโลก แต่"%s"%100000ไม่ได้ strทั่วโลกจะต้องมีการมองขึ้นในขอบเขตทั่วโลก สิ่งนี้ไม่ได้อธิบายถึงความแตกต่างทั้งหมด:

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

เท่าที่สังเกตจากthg435 ,

>>> Timer('"%s"%100000',).timeit()
0.034214019775390625
>>> Timer('"%s"%x','x=100000').timeit()
0.2940788269042969
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.