2016-07-28 19 views
10

Tôi đã điều tra máy phát điện Python và quyết định chạy thử nghiệm nhỏ.Tại sao máy phát điện được sản xuất bằng năng suất nhanh hơn máy phát điện do xrange sản xuất?

TOTAL = 100000000 
def my_sequence(): 
    i = 0 
    while i < TOTAL: 
     yield i 
     i += 1 

def my_list(): 
    return range(TOTAL) 

def my_xrange(): 
    return xrange(TOTAL)  

Bộ nhớ sử dụng (sử dụng psutil để có được bộ nhớ RSS quá trình) và thời gian thực hiện (sử dụng time.time()) được trình bày dưới đây sau khi chạy mỗi phương pháp nhiều lần và lấy trung bình:

sequence_of_values = my_sequence() # Memory usage: 6782976B Time taken: 9.53674e-07 s 

sequence_of_values2 = my_xrange() # Memory usage: 6774784B Time taken: 2.14576e-06 s 

list_of_values = my_list() # Memory usage: 3266207744B Time taken: 1.80253s 

Tôi nhận thấy rằng sản xuất một máy phát điện bằng cách sử dụng xrange là luôn (hơi) chậm hơn so với bằng cách sử dụng năng suất. Tại sao vậy?

+3

'xrange' là đối tượng chuỗi không phải là trình tạo, do đó nội bộ của chúng không giống hệt nhau. Bên cạnh đó, thời gian bạn đã đưa ra không thực sự cho thấy sự khác biệt đáng kể giữa xrange và trình tạo. Trong thực tế, sự khác biệt là không đáng kể – smac89

+0

Một điều cần sửa là thực sự tạo danh sách khi bạn sử dụng 'xrange'. Trong hàm 'my_xrange', bạn chỉ trả về xrange _generator_ (nó không thực sự là máy phát). Nhưng nó chưa được xử lý vào một danh sách đầy đủ. Vì vậy, nó có thể thậm chí còn chậm hơn so với những con số ở trên. – aneroid

+2

Bạn chỉ định thời gian cần thiết để xây dựng một máy phát điện và xây dựng một đối tượng 'xrange' - Bạn không đo lượng thời gian cần thiết để thực sự lặp lại trên các đối tượng này ... – mgilson

Trả lời

9

Tôi sẽ làm rõ câu trả lời này bằng cách nói rằng thời gian trên thang đo này có thể khó đo chính xác (có thể là tốt nhất để sử dụng timeit) và các loại tối ưu hóa này hầu như không bao giờ tạo ra sự khác biệt nào trong thực tế của bạn thời gian chạy chương trình ...

Ok, bây giờ từ chối trách nhiệm được thực hiện ...

điều đầu tiên mà bạn cần phải chú ý đó là bạn chỉ thời gian xây dựng của đối tượng phát/xrange - bạn đang KHÔNG thời gian mất bao lâu để thực sự lặp lại các giá trị . Có một vài lý do tại sao tạo trình tạo có thể nhanh hơn trong một số trường hợp hơn là tạo đối tượng xrange ...

  1. Trường hợp máy phát điện, bạn chỉ tạo máy phát điện - Không có mã nào trong máy phát điện thực sự được chạy. Số tiền này khoảng 1 cuộc gọi hàm.
  2. Đối với trường hợp xrange, bạn đang gọi hàm sau đó bạn đã để tra cứu tên toàn cầu xrange, toàn cầu TOTAL và sau đó bạn cần phải gọi BUILTIN đó - Như vậy, có có nhiều thứ được thực hiện trong trường hợp này.

Đối với bộ nhớ - Trong cả hai phương pháp lười, bộ nhớ được sử dụng sẽ bị chi phối bởi thời gian chạy python - Không phải bởi kích thước của đối tượng máy phát. Trường hợp duy nhất mà việc sử dụng bộ nhớ bị ảnh hưởng đáng kể bởi tập lệnh của bạn là trường hợp bạn xây dựng danh sách 100 triệu mục.

Cũng lưu ý rằng tôi không thể thực sự xác nhận kết quả của bạn liên tục trên hệ thống của tôi ... Sử dụng timeit, tôi thực sự nhận được rằng my_xrangeđôi khi nhanh hơn để xây dựng (bằng ~ 30%).

Thêm dòng sau vào dưới cùng của kịch bản của bạn:

from timeit import timeit 
print timeit('my_xrange()', setup='from __main__ import my_xrange') 
print timeit('my_sequence()', setup='from __main__ import my_sequence') 

Và kết quả của tôi là (cho CPython trên OS-X El-Capitan):

0.227491140366 
0.356791973114 

Tuy nhiên, pypy dường như ủng hộ việc xây dựng máy phát điện (tôi đã thử nó với cả hai my_xrange đầu tiên và my_sequence đầu tiên và có kết quả khá phù hợp mặc dù một trong những đầu tiên để chạy dường như được tại một chút bất lợi - Có lẽ do thời gian khởi động JIT hay như vậy mething):

0.00285911560059 
0.00137305259705 

Ở đây, tôi sẽ mong đợixrange để có chút lợi thế - nhưng một lần nữa, không có gì là đúng cho đến khi bạn timeit và sau đó nó chỉ đúng nếu sự khác biệt timings là đáng kể và nó chỉ đúng trên máy tính nơi bạn đã làm timings.
Xem khai mạc từ chối trách nhiệm :-P

+0

Và hơn nữa, "bộ nhớ tổng" được liệt kê trong hai trường hợp đầu tiên thực sự là bộ nhớ được sử dụng bởi thời gian chạy Python. – jsbueno

+1

@jsbueno - Oh yeah, tôi bỏ qua điều đó một chút. Nó không liên quan đến tất cả các trường hợp bởi trường hợp 'my_list' :-) – mgilson

3

Như tôi đã đề cập trong nhận xét của tôi ở trên, với chức năng máy phát điện của bạn và với xrange, bạn không thực sự tạo ra trình tự, chỉ đơn thuần là tạo ra các đối tượng. Câu trả lời của @ mgilson bao gồm các cuộc gọi liên quan đến tạo chúng.

Đối với thực sự làm một cái gì đó với họ:

>>> TOTAL = 100000 
>>> # your functions here 
... 
>>> import timeit 
>>> timeit.timeit("list(my_seq())", setup="from __main__ import my_seq", number=1000) 
9.783777457339898 
>>> timeit.timeit("list(my_xrange())", setup="from __main__ import my_xrange", number=1000) 
1.2652621698083024 
>>> timeit.timeit("list(my_list())", setup="from __main__ import my_list", number=1000) 
2.666709824464867 
>>> timeit.timeit("my_list()", setup="from __main__ import my_list", number=1000) 
1.2324339537661615 
  1. Bạn sẽ thấy rằng tôi là tạo ra một list ra của mỗi vì vậy tôi xử lý chuỗi.

  2. Chức năng của máy phát điện gần gấp 10 lần thời gian cho xrange.

  3. list(my_list) là không cần thiết kể từ my_list đã trả về danh sách sản xuất bởi range, vì vậy tôi đã làm điều đó một lần nữa mà không có cuộc gọi đến list().

  4. range gần giống với xrange nhưng đó là vì tôi đã giảm TOTAL. Sự khác biệt lớn nhất sẽ là rằng range sẽ tiêu thụ nhiều bộ nhớ hơn vì nó tạo toàn bộ danh sách đầu tiên và vì vậy chỉ mất dài hơn trong phần đó. Tạo một danh sách từ xrange = range, hiệu quả. Vì vậy, bộ nhớ cuối cùng được sử dụng sẽ giống nhau và vì tôi chỉ đang tạo danh sách ra khỏi xrange, thật khó để thấy sự khác biệt trong trường hợp tầm thường này.

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