Trong khi cố gắng trả lời What is the preferred way to compose a set from multiple lists in Python, tôi đã thực hiện một số phân tích hiệu suất và đưa ra một kết luận hơi ngạc nhiên.Tại sao tạo một tập hợp từ danh sách được nối nhanh hơn sử dụng `.update`?
Sử dụng
python -m timeit -s '
import itertools
import random
n=1000000
random.seed(0)
A = [random.randrange(1<<30) for _ in xrange(n)]
B = [random.randrange(1<<30) for _ in xrange(n)]
C = [random.randrange(1<<30) for _ in xrange(n)]'
cho các thiết lập, tôi timed các đoạn sau:
> $TIMEIT 'set(A+B+C)'
10 loops, best of 3: 872 msec per loop
> $TIMEIT 's = set(A); s.update(B); s.update(C)'
10 loops, best of 3: 930 msec per loop
> $TIMEIT 's = set(itertools.chain(A,B,C))'
10 loops, best of 3: 941 msec per loop
Trước sự ngạc nhiên của tôi, set(A+B+C)
là nhanh nhất mặc dù thực tế là nó tạo ra một danh sách trung gian chứa 3000000 yếu tố . .update
và itertools.chain
đều chậm hơn, mặc dù cả hai đều không sao chép bất kỳ danh sách nào.
Điều gì đang xảy ra ở đây?
EDIT: Trên một máy thứ hai (OS X 10.10.5, Python 2.7.10, 2.5GHz Core i7), tôi chạy đoạn mã sau (chạy các bài kiểm tra tới lui để tránh đặt hiệu ứng):
SETUP='import itertools
import random
n=1000000
random.seed(0)
A = [random.randrange(1<<30) for _ in xrange(n)]
B = [random.randrange(1<<30) for _ in xrange(n)]
C = [random.randrange(1<<30) for _ in xrange(n)]'
python -m timeit -s "$SETUP" 'set(A+B+C)'
python -m timeit -s "$SETUP" 's = set(A); s.update(B); s.update(C)'
python -m timeit -s "$SETUP" 's = set(itertools.chain(A,B,C))'
python -m timeit -s "$SETUP" 's = set(itertools.chain(A,B,C))'
python -m timeit -s "$SETUP" 's = set(A); s.update(B); s.update(C)'
python -m timeit -s "$SETUP" 'set(A+B+C)'
và thu được kết quả như sau:
10 loops, best of 3: 579 msec per loop
10 loops, best of 3: 726 msec per loop
10 loops, best of 3: 775 msec per loop
10 loops, best of 3: 761 msec per loop
10 loops, best of 3: 737 msec per loop
10 loops, best of 3: 555 msec per loop
Bây giờ set(A+B+C)
là rõ nhanh hơn, và kết quả là khá stabl e - khó có thể vạch ra điều này lên chỉ là lỗi đo lường. Chạy tập lệnh này nhiều lần sẽ tạo ra các kết quả tương tự.
Các đoán duy nhất tôi có thể làm được mà trường hợp đầu tiên trôi qua trong một danh sách có độ dài đã biết, và vì vậy có lẽ việc xây dựng bộ có thể chọn lựa yêu cầu bộ nhớ cơ bản một cách hợp lý hơn, ngược lại với hai bộ khác, nơi tập hợp được tạo và thay đổi kích thước hai lần (trường hợp thứ hai) hoặc được tạo với một trình lặp nội bộ nally nhiều lần. –
Trừ khi họ thay đổi 'set_init', đó không phải là cách nó hoạt động. ['set_init'] (http://svn.python.org/projects/python/trunk/Objects/setobject.c) chỉ cần gọi thẳng đến' set_update_internal' mà chỉ lặp lại trên các phần tử. (Tôi sẽ kéo từ 'hg.python.org' nhưng máy chủ đó có vẻ ở thời điểm này) – nneonneo
liên quan: [Kết hợp hai danh sách được sắp xếp bằng Python] (http://stackoverflow.com/a/482848/4279) – jfs