2012-05-31 39 views
10

Tôi đang tìm kiếm lời khuyên về các phương pháp triển khai đối tượng tồn tại lâu bền trong Python. Để chính xác hơn, tôi muốn có thể liên kết đối tượng Python với một tệp theo cách mà bất kỳ quá trình Python nào mở ra biểu diễn của tệp đó chia sẻ cùng một thông tin, bất kỳ quá trình nào cũng có thể thay đổi đối tượng của nó và các thay đổi sẽ lan truyền các quy trình khác, và ngay cả khi tất cả các quá trình "lưu trữ" đối tượng được đóng lại, tệp sẽ vẫn còn và có thể được mở lại bằng một tiến trình khác.Đối tượng Python kiên trì

Tôi tìm thấy ba ứng cử viên chính cho việc phân phối Python - anydbm, pickle và shelve (dbm có vẻ hoàn hảo, nhưng nó chỉ là Unix và tôi đang sử dụng Windows). Tuy nhiên, tất cả chúng đều có sai sót:

  • anydbm chỉ có thể xử lý từ điển giá trị chuỗi (Tôi muốn lưu trữ danh sách từ điển, tất cả đều có chuỗi khóa và giá trị chuỗi, mặc dù lý tưởng là tôi sẽ tìm kiếm mô-đun không có giới hạn loại)
  • giá đỡ yêu cầu phải mở lại tệp trước khi thay đổi tuyên truyền - ví dụ: nếu hai tiến trình A và B tải cùng một tệp (chứa danh sách trống được xếp hạng) và A thêm mục vào danh sách và các cuộc gọi sync(), B sẽ vẫn thấy danh sách là trống cho đến khi nó tải lại tệp.
  • dưa (mô-đun tôi hiện đang sử dụng để thực hiện thử nghiệm) có cùng "yêu cầu tải lại" làm giá và không ghi đè dữ liệu trước đó - nếu quá trình A kết thúc mười lăm chuỗi rỗng vào tệp và sau đó là chuỗi ' hello ', tiến trình B sẽ phải tải tệp tin mười sáu lần để nhận chuỗi' hello '. Tôi hiện đang xử lý vấn đề này bằng cách thực hiện bất kỳ thao tác ghi nào với lần đọc lặp lại cho đến khi kết thúc tệp ("xóa sạch slate trước khi viết trên đó") và bằng cách thực hiện mọi thao tác đọc lặp lại cho đến khi kết thúc tệp, nhưng tôi cảm thấy phải có Một cách tốt hơn.

mô-đun lý tưởng của tôi sẽ cư xử như sau (với "Một >>>" đại diện cho mã thực thi bởi quá trình A, và "B >>>" mã thực hiện bởi quá trình B):

A>>> import imaginary_perfect_module as mod 
B>>> import imaginary_perfect_module as mod 
A>>> d = mod.load('a_file') 
B>>> d = mod.load('a_file') 
A>>> d 
{} 
B>>> d 
{} 
A>>> d[1] = 'this string is one' 
A>>> d['ones'] = 1 #anydbm would sulk here 
A>>> d['ones'] = 11 
A>>> d['a dict'] = {'this dictionary' : 'is arbitrary', 42 : 'the answer'} 
B>>> d['ones'] #shelve would raise a KeyError here, unless A had called d.sync() and B had reloaded d 
11 #pickle (with different syntax) would have returned 1 here, and then 11 on next call 
(etc. for B) 

tôi có thể đạt được hành vi này bằng cách tạo mô-đun của riêng tôi sử dụng dưa chuột và chỉnh sửa hành vi đổ và tải để họ sử dụng các lần đọc lặp lại tôi đã đề cập ở trên - nhưng tôi thấy khó tin rằng vấn đề này chưa từng xảy ra và được khắc phục bằng , các lập trình viên tài năng hơn trước đây. Hơn nữa, những lần đọc lặp đi lặp lại này dường như không hiệu quả với tôi (mặc dù tôi phải thừa nhận rằng sự hiểu biết của tôi về độ phức tạp hoạt động bị giới hạn, và có thể là những lần đọc lặp lại này đang diễn ra "đằng sau hậu trường" trong các mô-đun rõ ràng mượt mà hơn như giá đỡ). Vì vậy, tôi kết luận rằng tôi phải thiếu một số mô-đun mã có thể giải quyết vấn đề cho tôi. Tôi rất biết ơn nếu có ai có thể chỉ cho tôi đúng hướng, hoặc đưa ra lời khuyên về việc thực hiện.

+4

tặng một cái nhìn cho 'Mongo-db'. Nó không được tích hợp hoàn toàn vào ngôn ngữ như ví dụ của bạn ở trên, nhưng nó sẽ cung cấp cho bạn một cơ sở dữ liệu mạnh mẽ hơn và khoan dung hơn là tẩy cho hệ thống tập tin và thông minh về khóa. – slezica

Trả lời

11

Sử dụng ZODB (Cơ sở dữ liệu đối tượng Zope) để thay thế. Được hỗ trợ với ZEO nó đáp ứng yêu cầu của bạn:

  • Transparent kiên trì cho Python đối tượng

    ZODB sử dụng dưa chua bên dưới để bất cứ điều gì đó là dưa-thể có thể được lưu trữ trong một cửa hàng đối tượng ZODB.

  • hỗ trợ giao dịch
  • Full ACID tương thích (bao gồm savepoints)

    Điều này có nghĩa thay đổi từ một quá trình tuyên truyền đến tất cả các quá trình khác khi họ là tốt và đã sẵn sàng, và mỗi tiến trình có một cái nhìn nhất quán trên các dữ liệu trong suốt một Giao dịch.

ZODB đã tồn tại hơn một thập kỷ nay, vì vậy bạn có quyền phỏng đoán vấn đề này đã được giải quyết trước đó. :-)

ZODB cho phép bạn cắm vào kho; định dạng phổ biến nhất là FileStorage, lưu trữ mọi thứ trong một Data.fs với bộ nhớ blob tùy chọn cho các đối tượng lớn.

Một số bộ lưu trữ ZODB là trình bao bọc xung quanh những người khác để thêm chức năng; DemoStorage ví dụ giữ các thay đổi trong bộ nhớ để tạo điều kiện cho việc kiểm tra đơn vị và thiết lập trình diễn (khởi động lại và bạn lại có slate sạch). BeforeStorage cung cấp cho bạn một cửa sổ đúng lúc, chỉ trả về dữ liệu từ các giao dịch trước một thời điểm nhất định. Sau này đã được công cụ trong việc phục hồi dữ liệu bị mất cho tôi.

ZEO là một plugin giới thiệu kiến ​​trúc máy khách-máy chủ. Sử dụng ZEO cho phép bạn truy cập vào một lưu trữ đã cho từ nhiều tiến trình tại một thời điểm; bạn sẽ không cần lớp này nếu tất cả những gì bạn cần là truy cập đa luồng chỉ từ một tiến trình.

Điều tương tự cũng có thể đạt được với RelStorage, lưu trữ dữ liệu ZODB trong cơ sở dữ liệu quan hệ như PostgreSQL, MySQL hoặc Oracle.

+0

ZODB nghe giống như những gì tôi muốn (và RelStorage nghe có vẻ thú vị để kiểm tra tương lai) - cảm ơn bạn! Tôi sẽ kiểm tra nó ra và trở lại để đánh dấu điều này là trả lời nếu nó làm việc cho tôi. – scubbo

+0

Tuyệt vời, cảm ơn vì lời khuyên! – scubbo

+0

Điều này nghe có vẻ giống như những gì tôi muốn; trên những gì giá đỡ cung cấp. – fatuhoku

2

Đối với người mới bắt đầu, bạn có thể cổng cơ sở dữ liệu xiên của bạn để cơ sở dữ liệu ZODB như thế này:

#!/usr/bin/env python 
import shelve 
import ZODB, ZODB.FileStorage 
import transaction 
from optparse import OptionParser 
import os 
import sys 
import re 

reload(sys) 
sys.setdefaultencoding("utf-8") 

parser = OptionParser() 

parser.add_option("-o", "--output", dest = "out_file", default = False, help ="original shelve database filename") 
parser.add_option("-i", "--input", dest = "in_file", default = False, help ="new zodb database filename") 

parser.set_defaults() 
options, args = parser.parse_args() 

if options.in_file == False or options.out_file == False : 
    print "Need input and output database filenames" 
    exit(1) 

db = shelve.open(options.in_file, writeback=True) 
zstorage = ZODB.FileStorage.FileStorage(options.out_file) 
zdb = ZODB.DB(zstorage) 
zconnection = zdb.open() 
newdb = zconnection.root() 

for key, value in db.iteritems() : 
    print "Copying key: " + str(key) 
    newdb[key] = value 

transaction.commit() 
Các vấn đề liên quan