2011-02-10 40 views
21

Tôi đã lược tả một số mã cũ mà tôi đã kế thừa với cProfile. Có một loạt các thay đổi mà tôi đã thực hiện đã giúp (như sử dụng phần mở rộng C của simplejson!).Tăng tốc độ ghi vào các tệp

Về cơ bản, tập lệnh này đang xuất dữ liệu từ một hệ thống sang tệp chiều rộng cố định ASCII. Mỗi hàng là một bản ghi và nó có nhiều giá trị. Mỗi dòng là 7158 ký tự và chứa một tấn không gian. Tổng số bản ghi là 1,5 triệu bản ghi. Mỗi hàng được tạo ra tại một thời điểm, và mất một thời gian (5-10 hàng một giây).

Khi mỗi hàng được tạo, nó được ghi vào đĩa đơn giản nhất có thể. Hồ sơ chỉ ra rằng khoảng 19-20% tổng thời gian được chi tiêu trong file.write(). Đối với một trường hợp thử nghiệm 1.500 hàng là 20 giây. Tôi muốn giảm số đó.

Giờ có vẻ như chiến thắng tiếp theo sẽ giảm lượng thời gian dành cho đĩa. Tôi muốn giảm nó, nếu có thể. Tôi có thể giữ một bộ nhớ đệm của các bản ghi trong bộ nhớ, nhưng tôi không thể đợi cho đến khi kết thúc và đổ tất cả cùng một lúc.

fd = open(data_file, 'w') 
for c, (recordid, values) in enumerate(generatevalues()): 
     row = prep_row(recordid, values) 
     fd.write(row) 
     if c % 117 == 0: 
       if limit > 0 and c >= limit: 
         break 
       sys.stdout.write('\r%s @ %s' % (str(c + 1).rjust(7), datetime.now())) 
       sys.stdout.flush() 

Suy nghĩ đầu tiên của tôi là lưu một bộ nhớ cache vào danh sách và ghi chúng theo lô. Điều đó có nhanh hơn không? Một cái gì đó như:

rows = [] 
for c, (recordid, values) in enumerate(generatevalues()): 
     rows.append(prep_row(recordid, values)) 
     if c % 117 == 0: 
      fd.write('\n'.join(rows)) 
      rows = [] 

Suy nghĩ thứ hai của tôi là sử dụng một sợi khác, nhưng điều đó khiến tôi muốn chết bên trong.

+0

Nút cổ chai của ứng dụng là gì? –

+2

Tôi nghĩ tôi đã rõ ràng. Đó là chi tiêu 20% thời gian của nó ghi vào đĩa một hàng tại một thời điểm. – chmullig

+0

Vâng, thực hiện thay đổi và cấu hình nó? Nó hy vọng nó sẽ có ít ảnh hưởng, vì tập tin I/O thường là dòng đệm ... hoặc vì vậy tôi giả định. – delnan

Trả lời

19

Việc ghi các ghi vào các nhóm 500 đã thực sự tăng tốc độ ghi đáng kể. Đối với trường hợp thử nghiệm này, các hàng ghi riêng lẻ mất 21.051 giây trong I/O, trong khi viết theo lô 117 mất 5.685 giây để viết cùng một số hàng. Các lô 500 chỉ mất 0.266 giây.

+3

và bây giờ bạn có thể thêm luồng cho các tập tin văn bản để làm asynhronus bằng văn bản – ted

+0

Tốt hơn - chỉ cần đầu ra để stdout, ống nó vào một tập tin và để cho hệ điều hành làm đệm và hàng loạt viết cho bạn. :) –

+0

@LesterCheung, bạn có thể xây dựng không? – blindguy

32

Thực ra, vấn đề của bạn không phải là file.write() mất 20% thời gian của bạn. Đó là 80% thời gian bạn không ở trong số file.write()!

Ghi vào đĩa chậm. Có thực sự không có gì bạn có thể làm về nó. Nó chỉ đơn giản là mất một số lượng rất lớn thời gian để viết công cụ ra đĩa. Có hầu như không có gì bạn có thể làm để tăng tốc độ nó lên.

Điều bạn muốn là thời gian I/O là phần lớn nhất của chương trình để tốc độ của bạn bị giới hạn bởi tốc độ của đĩa cứng không phải là thời gian xử lý của bạn. Lý tưởng là dành cho file.write() để sử dụng 100%!

+0

+1 và thông thường tôi đồng ý với bạn. Tuy nhiên trong trường hợp này, quá trình bên ngoài tôi đang sử dụng để tạo ra dữ liệu là siêu chậm và tôi muốn giảm thiểu mọi thứ khác càng nhiều càng tốt. Tôi cho rằng tôi nên nói chuyện trong vài giây, và tập trung vào việc giảm bớt điều đó. Sẽ chỉnh sửa để làm rõ # giây. – chmullig

+0

Đã cập nhật để xác định rằng mất 20 giây để ghi 1.500 bản ghi. Tôi thực sự quan tâm đến con số đó, tôi chỉ sử dụng phần trăm để chứng minh rằng nó thực sự đáng được tối ưu hóa. – chmullig

+0

@chmullig,% đang được chi tiêu cho quá trình bên ngoài? –

1

Bạn có thể làm mmap trong python, trong đó có thể trợ giúp. Nhưng tôi nghi ngờ bạn đã làm một số sai lầm trong khi profiling, bởi vì 7k * 1500 trong 20 giây là khoảng 0,5 Mbytes/s. Làm một bài kiểm tra trong đó bạn viết các dòng ngẫu nhiên với cùng độ dài, và bạn sẽ thấy nó nhanh hơn rất nhiều.

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