2013-02-20 24 views
10

Tôi đang cố gắng hiểu cách PyTables quản lý dữ liệu có kích thước lớn hơn kích thước bộ nhớ. Dưới đây là bình luận trong mã của PyTables (link to GitHub):PyTables xử lý dữ liệu với kích thước lớn hơn nhiều lần kích thước bộ nhớ

# Nodes referenced by a variable are kept in `_aliveNodes`. 
# When they are no longer referenced, they move themselves 
# to `_deadNodes`, where they are kept until they are referenced again 
# or they are preempted from it by other unreferenced nodes. 

Cũng bình luận hữu ích có thể được tìm thấy bên trong _getNode phương pháp. Có vẻ như PyTables có hệ thống đệm IO rất thông minh, như tôi hiểu, lưu trữ dữ liệu được người dùng tham chiếu trong bộ nhớ RAM nhanh như "aliveNodes", tiếp tục tham chiếu trước và dữ liệu không được coi là "deadNodes" để "hồi sinh" nhanh chóng khi cần và đọc dữ liệu từ đĩa nếu khóa được yêu cầu không có trong cả hai danh mục đã chết hoặc còn sống.

Tôi cần một số kiến ​​thức chuyên môn về cách chính xác PyTables xử lý các tình huống khi làm việc với dữ liệu lớn hơn bộ nhớ có sẵn sau đó. Câu hỏi cụ thể của tôi:

  1. Làm thế nào deadNode/aliveHệ thống làm việc của hệ thống (ảnh chung)?
  2. Điểm khác biệt chính giữa các tệp aliveNodes/deadNodes trong khi cả hai biểu thị dữ liệu được lưu trữ trong RAM nếu im phải không?
  3. Giới hạn RAM có thể điều chỉnh theo cách thủ công không? Bên dưới nhận xét, có mã đọc giá trị từ params['NODE_CACHE_SLOTS']. Nó có thể được xác định bằng cách nào đó bởi người dùng? Ví dụ, nếu tôi muốn để lại một số RAM cho các ứng dụng khác mà cần bộ nhớ quá?
  4. Trong những trường hợp nào, PyTables có thể gặp sự cố hoặc suy giảm đáng kể khi làm việc với số lượng lớn dữ liệu? Trong trường hợp của tôi có thể vượt quá bộ nhớ của 100 lần, những cạm bẫy phổ biến trong những tình huống như vậy là gì?
  5. Việc sử dụng PyTables có ý nghĩa gì về kích thước, cấu trúc dữ liệu và thao tác với dữ liệu được coi là 'đúng' để đạt được hiệu suất tốt nhất?
  6. Docs suggests sử dụng .flush() sau mỗi chu kỳ .append() cơ bản. Chu kỳ này thực sự có thể kéo dài trong bao lâu? Im thực hiện một điểm chuẩn nhỏ, so sánh SQLite và PyTables trong cách họ có thể xử lý việc tạo ra một bảng lớn với các cặp khóa-giá trị từ các tệp CSV lớn. Và khi tôi sử dụng .flush(), ít thường xuyên hơn trong chu kỳ chính, PyTables tăng tốc độ rất lớn. Vậy - liệu có đúng không, là .append() khối dữ liệu tương đối lớn và sau đó sử dụng .flush()?
+2

Bạn không thể lưu trữ nội dung trong bộ nhớ 100x RAM có sẵn của bạn. Tuy nhiên, PyTables có thể giúp bạn truy cập dữ liệu theo khối hoặc áp dụng các chức năng cho dữ liệu của bạn theo cách hiệu quả về bộ nhớ (đôi khi). Bạn đang cố gắng làm gì với dữ liệu của mình? – seandavi

Trả lời

2

Cấu trúc bộ nhớ

pytables

Không bao giờ được sử dụng nhưng nhìn vào mã nguồn:

class _Deadnodes(lrucacheExtension.NodeCache): 
    pass 

Vì vậy, nó trông giống như _deadnodes được thực hiện sử dụng một bộ nhớ cache LRU. LRU == "Ít nhất được sử dụng gần đây" có nghĩa là nó sẽ vứt bỏ nút ít được sử dụng đầu tiên. nguồn là here.

class _AliveNodes(dict): 
    ... 

Chúng sử dụng làm từ điển tùy chỉnh các nút đang chạy và được trình bày thực sự trong chương trình.

ví dụ rất đơn giản (nút là chữ cái, số trong bộ nhớ cache cho biết cách cũ một mục là):

memory of 4, takes 1 time step 
cache with size 2, takes 5 times steps 
disk with much much more, takes 50 time steps 

get node A //memory,cache miss load from disk t=50 
get node B // "" t=100 
get node C // "" t=150 
get node D // "" t=200 
get node E // "" t=250 
get node A //cache hit load from cache t=255 
get node F //memory, cache miss load from disk t=305 
get node G //memory, cache miss load from disk t=355 
get node E // in memory t=356 (everything stays the same) 

t=200    t=250    t=255 
Memory CACHE Memory CACHE Memory CACHE 
A     E   A0  E   B0 
B     B     A 
C     C     C 
D     D     D 

t=305    t=355    
Memory CACHE Memory CACHE 
E   B1  E   G0 
A   C0  A   C1 
F     F 
D     G 

Như bạn đã biết trong cuộc sống thực những cấu trúc là rất lớn và thời gian cần thiết để truy cập chúng là trong chu kỳ xe buýt, vì vậy 1/(đồng hồ của máy của bạn).

So sánh thời gian cần để truy cập các phần tử giống nhau. Nó là khá không đáng kể trong bộ nhớ, nhiều hơn một chút cho bộ nhớ cache, và nhiều hơn cả cho đĩa. Đọc từ đĩa là phần dài nhất của toàn bộ quá trình. đĩa và cánh tay cần di chuyển, vv Nó là một quá trình vật lý chứ không phải là một quá trình điện tử, như trong nó không xảy ra ở tốc độ ánh sáng.

Ở đây trong các ô, chúng thực hiện tương tự. Họ đã viết thuật toán bộ nhớ cache của riêng mình trong Cython là một người đàn ông trung gian giữa các nút còn sống (bộ nhớ) và dữ liệu đầy đủ (đĩa). Nếu có quá thấp tỷ lệ truy cập thì có vẻ như bộ nhớ cache sẽ bị tắt và sau một số chu kỳ nhất định, nó sẽ bật lại.

Trong parameters.py các DISABLE_EVERY_CYCLE, ENABLE EVERY_CYCLELOWEST_HIT_RATIO biến được sử dụng để xác định số lượng các chu kỳ dưới LOWEST_HIT_RATIO để vô hiệu hóa sau và số lượng các chu kỳ đợi để bật lại. Thay đổi các giá trị này không được khuyến khích.

Điều chính bạn nên thực hiện từ việc này là nếu bạn cần xử lý trên tập dữ liệu lớn, hãy đảm bảo chúng nằm trên cùng một nút. Nếu bạn có thể lấy đi với nó, đọc trong một đoạn, làm chế biến trên mâm cặp đó, có được kết quả của bạn, sau đó tải một đoạn khác. Nếu bạn tải đoạn A, lấy một đoạn B khác, sau đó nạp đoạn A một lần nữa, điều này sẽ gây ra sự chậm trễ nhất. Chỉ hoạt động trên một đoạn dữ liệu tại một thời điểm và giữ quyền truy cập và ghi ở mức tối thiểu. Khi giá trị nằm trong _alivenodes, hãy nhanh chóng sửa đổi nó, _deadnodes chậm hơn một chút và không chậm hơn nhiều.

NODE_CACHE_SLOTS

params['NODE_CACHE_SLOTS'] xác định kích thước của tập hợp các nút chết. Truy tìm nó trở lại parameters.py nó mặc định là 64. Nó nói rằng bạn có thể thử các giá trị khác nhau và báo cáo lại. Bạn có thể thay đổi giá trị trong tệp hoặc thực hiện:

import parameters 
parameters.NODE_CACHE_SLOTS = # something else 

Điều này chỉ giới hạn số lượng nút được lưu trong bộ nhớ cache. Quá khứ bạn bị giới hạn bởi kích thước heap của python, để thiết lập xem this.

append/tuôn

Đối append, flush đảm bảo các hàng được xuất ra để bàn.Càng có nhiều dữ liệu bạn đang di chuyển với điều này càng lâu thì dữ liệu sẽ chuyển từ bộ đệm nội bộ sang cấu trúc dữ liệu. Nó đang gọi một phiên bản sửa đổi của hàm H5TBwrite_records với mã xử lý khác. Tôi đoán chiều dài của cuộc gọi để xác định chu kỳ đầu ra là bao lâu.

Hãy nhớ rằng đây là tất cả từ mã nguồn và không xem xét bất kỳ phép thuật bổ sung nào mà họ đang cố gắng thực hiện. Tôi chưa bao giờ sử dụng thuốc thử. Về lý thuyết, nó không nên sụp đổ, nhưng chúng ta không sống trong một thế giới lý thuyết.

Edit:

Trên thực tế việc tìm kiếm một nhu cầu cho bản thân mình pytables Tôi đã đi qua this question trong faq của họ mà có thể trả lời một số mối quan tâm của bạn.

Cảm ơn bạn đã tiết lộ pytables cho tôi, nếu tôi đã xem qua .h5 tệp trước khi nghiên cứu câu hỏi này, tôi sẽ không biết phải làm gì.

1

Tôi không phải là chuyên gia trong PyTable nhưng rất có thể hoạt động như swap memory.

aliveNodes sống trong RAM trong khi deadNodes có thể được lưu trữ trên đĩa trong tệp hdf5 (định dạng tệp nhị phân được PyTables sử dụng). Mỗi khi bạn cần truy cập một phần dữ liệu, nó cần phải nằm trong RAM. Vì vậy, PyTable kiểm tra nếu nó đã có (aliveNodes) và trả lại cho bạn nếu nó được. Nếu không, cần phải hồi sinh số deadNode nơi dữ liệu đang hoạt động. Vì RAM bị hạn chế, có thể sẽ giết (ghi vào đĩa) một số chưa sử dụng aliveNode để thực hiện một số phòng trước.

Lý do cho quá trình này tất nhiên là kích thước giới hạn của RAM. Hậu quả là các buổi biểu diễn bị ảnh hưởng mỗi lần bạn cần trao đổi một nút (giết một nút và hồi sinh một nút khác).

Để tối ưu hóa hiệu suất, bạn nên cố gắng giảm thiểu trao đổi. Ví dụ: nếu dữ liệu của bạn có thể được xử lý song song, bạn chỉ có thể tải từng nút một lần. Ví dụ khác: hãy tưởng tượng rằng bạn cần lặp qua mọi phần tử của một ma trận lớn được chia thành một mạng lưới các nút. Sau đó, bạn nên tránh truy cập các phần tử của nó theo hàng hoặc theo cột mà đúng hơn là nút theo nút.

Tất nhiên PyTable xử lý điều này dưới mui xe, do đó bạn không cần phải kiểm soát những gì trong mỗi nút (nhưng tôi khuyến khích bạn khai thác biến này NODE_CACHE_SLOTS, ít nhất là để hiểu cách hoạt động). Nhưng nói chung, nó nhanh hơn để truy cập dữ liệu liền kề hơn là rải rác khắp nơi. Như mọi khi, nếu hiệu suất thời gian là một vấn đề quan trọng đối với (các) ứng dụng của bạn, hãy lập hồ sơ cho mã của bạn.


dịch: Tôi hầu như không biết gì về PyTables

0

Tôi cũng không phải là một chuyên gia trong PyTable, và Simon dường như đã bao phủ các khái niệm về bộ nhớ swap độc đáo, NHƯNG nếu bạn muốn có một ví dụ cụ thể về thuật toán được thiết kế để xử lý dữ liệu quá lớn để vừa với bộ nhớ, tôi khuyên bạn nên xem xét sắp xếp bên ngoài.

Ý tưởng cơ bản là: bạn không thể phù hợp với tất cả dữ liệu của mình trong bộ nhớ, nhưng bạn cần sắp xếp nó. Tuy nhiên, bạn có thể phù hợp với một số dữ liệu trong bộ nhớ, trong các khối có kích thước là. Nói rằng có j khối như vậy.

  • Chia dữ liệu thành các khối có kích thước k.
  • Đối với mỗi khối, hãy đưa nó vào bộ nhớ và sắp xếp nó (ví dụ: sử dụng quicksort hoặc bất kỳ thứ gì), sau đó viết phiên bản được sắp xếp lại vào đĩa.

Bây giờ, chúng tôi có khối j dữ liệu được sắp xếp mà chúng tôi muốn hợp nhất thành một đoạn dữ liệu được sắp xếp dài. Vấn đề đó nghe có vẻ giống như mergesort! Vì vậy,

  • Mang giá trị thấp nhất từ ​​mỗi j sắp xếp các khối vào bộ nhớ
  • Tìm nhỏ nhất của những giá trị j. Đó là phần dữ liệu nhỏ nhất! Vì vậy, hãy ghi nó vào đĩa ở đâu đó khi bắt đầu tập dữ liệu được sắp xếp của chúng tôi.
  • Thay thế giá trị mới được viết với giá trị nhỏ nhất tiếp theo từ khối của nó vào bộ nhớ (đây là bit 'trao đổi' bộ nhớ hoán đổi).

Hiện tại, dữ liệu trong bộ nhớ là nhỏ nhất j, ngoại trừ dữ liệu chúng tôi đã viết vào tập dữ liệu được sắp xếp cuối cùng trên đĩa. Vì vậy, nếu chúng ta lặp lại quá trình đó cho đến khi tất cả dữ liệu được ghi vào tập cuối cùng, nó sẽ luôn luôn được sắp xếp.

Vì vậy, đó chỉ là một ví dụ về thuật toán sử dụng trao đổi bộ nhớ để xử lý dữ liệu quá lớn để vừa với bộ nhớ. Các phương thức sắp xếp của PyTable có lẽ nằm dọc theo các dòng này.

Phần thưởng: Heresome liên kết to giải thích thêm về sắp xếp bên ngoài.