2013-03-21 28 views
6

Tôi sử dụng bộ sưu tập tập hợp Python để lưu trữ các đối tượng duy nhất. Mọi đối tượng đều có __hash____eq__ ghi đè.Python rất lớn. Làm thế nào để tránh ra khỏi ngoại lệ bộ nhớ?

Tập hợp chứa gần 200 000 đối tượng. Các thiết lập chính nó mất gần 4 GB bộ nhớ. Nó hoạt động tốt trên máy với hơn 5 GB, nhưng bây giờ tôi có một nhu cầu để chạy các kịch bản trên một máy tính mà chỉ có 3 GB RAM có sẵn.

Tôi viết lại tập lệnh thành C# - thực sự đọc cùng một dữ liệu từ cùng một nguồn, đặt nó vào một tương tự CLR của bộ (HashSet) và thay vì 4 GB, mất gần 350 MB trong khi tốc độ thực thi tập lệnh là tương đối giống nhau (gần 40 giây) Nhưng tôi phải sử dụng Python.

Q1: Python có bất kỳ bộ "đĩa liên tục" hay bất kỳ cách giải quyết nào khác không? Tôi đoán rằng nó có thể lưu trữ trong bộ nhớ chỉ "chìa khóa" dữ liệu được sử dụng trong các phương pháp băm/eq và mọi thứ khác có thể được lưu vào đĩa. Hoặc có thể có các cách giải quyết khác trong Python để có một bộ sưu tập các đối tượng duy nhất có thể chiếm nhiều bộ nhớ hơn so với sẵn có trong hệ thống.

Q2: câu hỏi ít thực tế hơn: tại sao bộ python mất quá nhiều bộ nhớ cho một bộ?

Tôi sử dụng Python chuẩn 2.7.3 trên 64 bit Ubuntu 12.10

Cảm ơn bạn.

Update1: kịch bản gì:

  1. đã đọc rất nhiều tài liệu JSON bán cấu trúc (mỗi JSON bao gồm đối tượng serialized với bộ sưu tập của các đối tượng tổng hợp liên quan đến nó)

  2. Parse mỗi Tài liệu JSON để lấy nó từ đối tượng chính và các đối tượng từ các bộ sưu tập tổng hợp. Mỗi đối tượng được phân tích cú pháp được lưu vào một tập hợp. Set được sử dụng để lưu trữ các đối tượng duy nhất. Thứ nhất, tôi đã sử dụng một cơ sở dữ liệu, nhưng ràng buộc duy nhất trong cơ sở dữ liệu hoạt động chậm hơn x100-x1000. Mỗi tài liệu JSON được phân tích cú pháp thành 1-8 loại đối tượng khác nhau. Mỗi loại đối tượng được lưu trữ trong tập hợp riêng của nó để lưu vào bộ nhớ chỉ các đối tượng duy nhất.

  3. Tất cả dữ liệu được lưu trữ trong bộ được lưu vào cơ sở dữ liệu quan hệ với các ràng buộc duy nhất. Mỗi bộ được lưu trữ trong bảng cơ sở dữ liệu riêng biệt.

Toàn bộ ý tưởng của kịch bản để lấy dữ liệu phi cấu trúc, loại bỏ bản sao từ bộ sưu tập đối tượng tổng hợp trong tài liệu JSON và lưu trữ dữ liệu có cấu trúc cơ sở dữ liệu quan hệ.

Cập nhật 2:

2 delnan: Tôi nhận xét tất cả các dòng mã với việc thêm vào một bộ khác nhau giữ tất cả các nhân viên khác (nhận được dữ liệu, phân tích, lặp lại) giống nhau - Các kịch bản mất 4 GB bộ nhớ ít.

Điều đó có nghĩa là khi những đối tượng 200K đó được thêm vào bộ - chúng bắt đầu lấy quá nhiều bộ nhớ. Đối tượng là một dữ liệu phim đơn giản từ TMDB - ID, một danh sách các thể loại, một danh sách các diễn viên, đạo diễn, rất nhiều chi tiết phim khác và có thể mô tả phim lớn từ Wikipedia.

+3

Tại sao bạn không sử dụng cơ sở dữ liệu? –

+0

Đối tượng chứa dữ liệu nào? Bạn có thể đăng một số mã? – TAS

+1

Bạn có thể thử lưu trữ chúng trong một [giá đỡ] (http://docs.python.org/library/shelve.html), sử dụng băm làm khóa. – georg

Trả lời

4

Sets thực sự sử dụng nhiều bộ nhớ, nhưng danh sách thì không.

>>> from sys import getsizeof 
>>> a = range(100) 
>>> b = set(a) 
>>> getsizeof(a) 
872 
>>> getsizeof(b) 
8424 
>>> 

Nếu lý do duy nhất tại sao bạn sử dụng bộ này là để ngăn trùng lặp, tôi khuyên bạn nên sử dụng danh sách thay thế. Bạn có thể ngăn chặn các bản sao bằng cách kiểm tra nếu các đối tượng đã có trong danh sách của bạn trước khi thêm chúng. Nó có thể chậm hơn so với việc sử dụng các bộ máy tích hợp sẵn, nhưng chắc chắn nó sẽ sử dụng ít bộ nhớ hơn.

2

Thử sử dụng __slots__ để giảm mức sử dụng bộ nhớ của bạn.

Khi tôi gặp vấn đề này với rất nhiều và nhiều đối tượng, sử dụng __slots__ sẽ giảm mức sử dụng bộ nhớ xuống 1/3.

Dưới đây là một số SO question about __slots__ bạn có thể thấy thú vị.

5

Cách tiếp cận tốt nhất có thể là để làm cho các đối tượng mà bạn đang lưu trữ trong tập hợp nhỏ hơn. Nếu chúng chứa các trường không cần thiết, hãy loại bỏ chúng.

Để giảm chi phí đối tượng chung, bạn cũng có thể sử dụng __slots__ để khai báo các lĩnh vực sử dụng:

class Person(object): 
    __slots__ = ['name', 'age'] 
    def __init__(self): 
     self.name = 'jack' 
     self.age = 99 
+0

Giả sử CPython. PyPy thực hiện tối ưu hóa tương tự cho hầu hết các đối tượng mà không cần bạn chỉ định '__slots__' IIRC. – delnan

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