2010-05-04 31 views
19

Tôi mất đến một giờ để đọc cấu trúc dữ liệu đồ thị NetworkX 1 GB sử dụng cPickle (1 GB khi được lưu trữ trên đĩa dưới dạng tệp nhị phân).Làm thế nào tôi có thể tăng tốc độ tháo các đối tượng lớn nếu tôi có nhiều RAM?

Lưu ý rằng tệp sẽ nhanh chóng tải vào bộ nhớ. Nói cách khác, nếu tôi chạy:

import cPickle as pickle 

f = open("bigNetworkXGraph.pickle","rb") 
binary_data = f.read() # This part doesn't take long 
graph = pickle.loads(binary_data) # This takes ages 

Làm cách nào để tăng tốc hoạt động cuối cùng này?

Lưu ý rằng tôi đã thử tẩy dữ liệu cả khi sử dụng cả hai giao thức nhị phân (1 và 2) và dường như không tạo ra sự khác biệt nhiều cho giao thức mà tôi sử dụng. Cũng lưu ý rằng mặc dù tôi đang sử dụng hàm "tải" (có nghĩa là "chuỗi tải") ở trên, nó đang tải dữ liệu nhị phân, chứ không phải dữ liệu ascii.

Tôi có 128 GB bộ nhớ RAM trên hệ thống tôi đang sử dụng, vì vậy tôi hy vọng rằng ai đó sẽ cho tôi biết cách tăng bộ đệm đọc được chôn vùi trong triển khai dưa.

+0

Bạn có thực sự có nghĩa là 128 GB RAM không? Hoặc 128MB? –

+0

Tôi có nghĩa là GB ram, không phải MB. – conradlee

+0

cảm thấy đau của bạn ngay bây giờ .., – dcousens

Trả lời

6

Có lẽ bạn đang bị ràng buộc bởi Python tạo đối tượng/phân bổ chi phí, không phải là unpickling riêng của mình. Nếu vậy, có rất ít bạn có thể làm để tăng tốc độ này, ngoại trừ việc không tạo ra tất cả các đối tượng. Bạn có cần toàn bộ cấu trúc cùng một lúc không? Nếu không, bạn có thể sử dụng dân số lười biếng của cấu trúc dữ liệu (ví dụ: đại diện cho các phần của cấu trúc bằng các chuỗi được chọn, sau đó bỏ chọn chúng chỉ khi chúng được truy cập).

+0

Được rồi, tôi có thể nghĩ ra một số cách để chia nhỏ dữ liệu này ở mức độ nào đó, (đặt thuộc tính nút trong các tệp khác nhau), nhưng các cạnh của đối tượng biểu đồ chiếm một bộ nhớ rất nhiều --- và nếu tôi phải lưu trữ các tệp này trong các tệp khác nhau và điền lại biểu đồ của tôi mỗi lần tôi sử dụng nó, sau đó là điểm của việc tuần tự hóa? Tôi cũng có thể lưu trữ dữ liệu đồ thị của mình trong danh sách cạnh. – conradlee

+3

Tôi thực sự không nghĩ rằng serialization là giải pháp tốt nhất cho vấn đề của bạn. Pickle không bao giờ có nghĩa là có khả năng mở rộng cho các cấu trúc dữ liệu khổng lồ. Đây là nhiều lĩnh vực của các định dạng giống như cơ sở dữ liệu hỗ trợ truy cập ngẫu nhiên và tải theo yêu cầu. – wump

-3

tại sao bạn không sử dụng pickle.load?

f = open('fname', 'rb') 
graph = pickle.load(f) 
+0

Điều đó có thể sẽ không giúp ích gì; phần đọc đủ nhanh và có đủ bộ nhớ, vì vậy việc bỏ chọn trực tiếp từ luồng sẽ không đạt được nhiều. – wump

+0

Đó là điều đầu tiên tôi thử. Tôi cho thấy cách phức tạp hơn để tải một tập tin dưa để minh họa rằng đọc dữ liệu nhị phân vào ram không có vẻ là nút cổ chai. – conradlee

0

Có lẽ điều tốt nhất bạn có thể làm là để phân chia các dữ liệu lớn vào đối tượng nhỏ nhất nhỏ hơn, chúng ta hãy nói, hơn 50MB, do đó có thể được lưu trữ trong ram, và tái kết hợp nó.

Afaik không có cách nào để tự động tách dữ liệu thông qua mô-đun dưa, vì vậy bạn phải tự mình làm.

Dù sao, một cách khác (đó là khá khó khăn hơn) là sử dụng một số NoSQL Database như MongoDB để lưu trữ dữ liệu của bạn ...

+0

anh ta có RAM 128 GB, tại sao anh ta lại làm tất cả việc chia tách? – SilentGhost

+0

Tôi đoán anh ấy muốn viết 128 MB ram ... –

+0

Không, ý tôi là 128 GB - đó là một cỗ máy lớn. Tôi cũng đã có 24 lõi để sử dụng, do đó, một giải pháp song song sẽ được tốt đẹp, mặc dù tôi đoán GIL sẽ không thực sự làm cho điều này có thể. – conradlee

4

Tại sao bạn không thử marshaling dữ liệu của mình và lưu trữ trong RAM bằng memcached (ví dụ). Có, nó có một số hạn chế nhưng như this chỉ ra marshaling là cách nhanh hơn (20 đến 30 lần) so với tẩy.

Tất nhiên, bạn cũng nên dành nhiều thời gian tối ưu hóa cấu trúc dữ liệu để giảm thiểu số lượng và độ phức tạp của dữ liệu bạn muốn lưu trữ.

1

Điều này thật lố bịch.

Tôi có một từ điển lớn ~ 150MB (collections.Counter thực sự) mà tôi đã đọc và viết bằng cPickle ở định dạng nhị phân.

Viết mất khoảng 3 phút.
Tôi dừng đọc nó ở mốc 16 phút, với RAM của tôi hoàn toàn bị nghẹt thở.

bây giờ tôi đang sử dụng soái, và phải mất: ghi: ~ 3s
đọc: ~ 5s

Tôi chọc xung quanh một chút, và tình cờ gặp article này.
Đoán tôi chưa bao giờ xem xét nguồn cúp, nhưng nó xây dựng toàn bộ VM để tái tạo lại từ điển?
Nên có một lưu ý về hiệu suất trên các đối tượng rất lớn trong tài liệu IMHO.

0

Nói chung, tôi đã thấy rằng nếu có thể, khi lưu các đối tượng lớn vào đĩa trong python, sẽ hiệu quả hơn nhiều khi sử dụng các ma trận lộn xộn hoặc ma trận scipy.sparse. Do đó đối với các đồ thị khổng lồ như đồ thị trong ví dụ, tôi có thể chuyển đồ thị thành ma trận thưa thớt scipy (networkx có chức năng thực hiện điều này, và không khó để viết), và sau đó lưu ma trận thưa thớt đó vào định dạng nhị phân.

1

Tôi cũng đang cố gắng tăng tốc tải/lưu trữ biểu đồ mạngx. Tôi đang sử dụng phương pháp adjacency_graph để chuyển đổi đồ thị một cái gì đó serialisable, xem ví dụ mã này:

from networkx.generators import fast_gnp_random_graph 
from networkx.readwrite import json_graph 

G = fast_gnp_random_graph(4000, 0.7) 

with open('/tmp/graph.pickle', 'wb+') as f: 
    data = json_graph.adjacency_data(G) 
    pickle.dump(data, f) 

with open('/tmp/graph.pickle', 'rb') as f: 
    d = pickle.load(f) 
    H = json_graph.adjacency_graph(d) 

Tuy nhiên, phương pháp adjacency_graph chuyển đổi này là khá chậm, vì vậy thời gian đạt được trong tẩy có lẽ bị mất trên chuyển đổi.

Vì vậy, điều này thực sự không tăng tốc độ, bummer. Chạy mã này cung cấp các thời gian sau:

N=1000 

    0.666s ~ generating 
    0.790s ~ converting 
    0.237s ~ storing 
    0.295s ~ loading 
    1.152s ~ converting 

N=2000 

    2.761s ~ generating 
    3.282s ~ converting 
    1.068s ~ storing 
    1.105s ~ loading 
    4.941s ~ converting 

N=3000 

    6.377s ~ generating 
    7.644s ~ converting 
    2.464s ~ storing 
    2.393s ~ loading 
    12.219s ~ converting 

N=4000 

    12.458s ~ generating 
    19.025s ~ converting 
    8.825s ~ storing 
    8.921s ~ loading 
    27.601s ~ converting 

Tăng trưởng theo cấp số nhân này có thể do biểu đồ nhận được nhiều cạnh hơn theo cấp số nhân. Dưới đây là một ý chính kiểm tra, trong trường hợp bạn muốn thử mình

https://gist.github.com/wires/5918834712a64297d7d1

6

tôi đã thành công rực rỡ trong việc đọc một ~ 750 MB cấu ​​trúc dữ liệu igraph (một tập tin nhị phân dưa) sử dụng cPickle riêng của mình. Điều này đạt được bằng cách đơn giản gói lên cuộc gọi tải dưa như đã đề cập here

đoạn Ví dụ trong trường hợp của bạn sẽ là một cái gì đó như:

import cPickle as pickle 
import gc 

f = open("bigNetworkXGraph.pickle", "rb") 

# disable garbage collector 
gc.disable() 

graph = pickle.load(f) 

# enable garbage collector again 
gc.enable() 
f.close() 

này chắc chắn không phải là cách thích hợp nhất để làm điều đó, tuy nhiên, nó làm giảm thời gian cần thiết.
(Đối với tôi, nó giảm từ 843,04 xuống còn 41,28 giây, khoảng 20x)

+0

tại sao bạn cần bật lại gc? Và sẽ pickle từ Python3 với giao thức = 4 được hiệu quả hơn? – alvas

+0

@alvas không phải là cách hay để giữ cho gc được bật theo mặc định? Ngoài ra, tôi đã không cố gắng giao thức = 4 từ Python3 nhưng w.r.t kịch bản trên. –

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