2015-05-18 14 views
14

Tôi có nhiều tệp phân cách tab 3GB. Có 20 triệu hàng trong mỗi tệp. Tất cả các hàng phải được xử lý độc lập, không có mối quan hệ giữa hai hàng. Câu hỏi của tôi là, những gì sẽ nhanh hơn A. dòng Reading bởi dòng sử dụng `Python: Cách nhanh nhất để xử lý tệp lớn

with open() as infile: 
      for line in infile: 

Hoặc B. Đọc các tập tin vào bộ nhớ trong khối và xử lý nó, nói 250 MB tại một thời điểm?

Quá trình xử lý không phức tạp lắm, tôi chỉ lấy giá trị trong cột1 đến List1, cột2 đến Danh sách 2, v.v. Có thể cần phải thêm một số giá trị cột cùng nhau.

Tôi đang sử dụng python 2.7 trên hộp linux có bộ nhớ 30 GB. Văn bản ASCII.

Bất kỳ cách nào để tăng tốc độ song song? Ngay bây giờ tôi đang sử dụng phương pháp cũ và quá trình này rất chậm. Có sử dụng bất kỳ mô-đun CSVReader nào để trợ giúp không? Tôi không phải làm điều đó trong python, bất kỳ ý tưởng sử dụng cơ sở dữ liệu hoặc ngôn ngữ nào khác đều được chào đón. Cảm ơn.

`

+0

đa xử lý; đọc lặp đi lặp lại chunked. Tại 3GB cho mỗi tập tin bạn ** KHÔNG ** muốn được đọc hoàn toàn vào bộ nhớ; bạn có thể thổi tài nguyên bộ nhớ của bạn. –

+0

Có vẻ như một cơ sở dữ liệu sẽ giúp bạn tùy thuộc vào loại xử lý mà bạn đang thực hiện. – squiguy

+0

Không nếu đây là nhiệm vụ đơn lẻ; Dữ liệu trong; Chế biến; dữ liệu ra; xóa dữ liệu nguồn. –

Trả lời

23

Có vẻ như mã của bạn là I/O bị ràng buộc. Điều này có nghĩa là đa xử lý sẽ không giúp ích gì - nếu bạn dành 90% thời gian đọc từ đĩa, có thêm 7 quy trình đang chờ đọc tiếp theo sẽ không giúp gì cả.

Và, trong khi sử dụng mô-đun đọc CSV (cho dù số csv hoặc thứ gì đó như NumPy hoặc Pandas) có thể là một ý tưởng hay để đơn giản, nó không tạo ra sự khác biệt nhiều về hiệu suất.

Tuy nhiên, bạn nên kiểm tra xem bạn thực sự bị ràng buộc I/O, thay vì chỉ đoán. Chạy chương trình của bạn và xem liệu mức sử dụng CPU của bạn có gần 0% hay gần 100% hay một lõi. Làm những gì Amadan đề xuất trong một bình luận, và chạy chương trình của bạn chỉ với pass để xử lý và xem liệu nó cắt giảm 5% thời gian hay 70%. Thậm chí bạn có thể thử so sánh với một vòng lặp qua os.openos.read(1024*1024) hoặc thứ gì đó và xem liệu có nhanh hơn không.


Kể từ khi bạn sử dụng Python 2.x, Python dựa vào thư viện stdio C để đoán số lượng bộ đệm cùng một lúc, do đó có thể buộc phải đệm nhiều hơn. Cách đơn giản nhất để làm điều đó là sử dụng readlines(bufsize) cho một số lớn bufsize. (Bạn có thể thử các con số khác nhau và đo chúng để xem điểm cao nhất là ở đâu. Theo kinh nghiệm của tôi, thường là bất cứ thứ gì từ 64K-8MB đều giống nhau, nhưng tùy thuộc vào hệ thống của bạn có thể khác - đặc biệt nếu bạn đang đọc ra một hệ thống tập tin mạng với thông lượng lớn nhưng độ trễ kinh khủng rằng đầm lầy thông-vs-độ trễ của ổ đĩa vật lý thực tế và bộ nhớ đệm hệ điều hành nào)

vì vậy, ví dụ:.

bufsize = 65536 
with open(path) as infile: 
    while True: 
     lines = infile.readlines(bufsize) 
     if not lines: 
      break 
     for line in lines: 
      process(line) 

Trong khi đó, giả sử bạn đang sử dụng hệ thống 64 bit, bạn có thể thử sử dụng mmap thay vì đọc tệp ở vị trí đầu tiên. Điều này chắc chắn không phải là được bảo đảm để tốt hơn, nhưng nó có thể trở nên tốt hơn, tùy thuộc vào hệ thống của bạn.Ví dụ:

with open(path) as infile: 
    m = mmap.mmap(infile, 0, access=mmap.ACCESS_READ) 

Một Python mmap là sắp xếp của một lạ đối tượng nó hoạt động như một str và giống như một file cùng một lúc, vì vậy bạn có thể, ví dụ, tay quét lặp cho dòng mới, hoặc bạn có thể gọi readline trên đó như thể nó là một tập tin. Cả hai đều sẽ xử lý nhiều hơn từ Python so với việc lặp lại tập tin dưới dạng dòng hoặc thực hiện hàng loạt readlines (bởi vì một vòng lặp trong C bây giờ là bằng Python thuần túy… mặc dù có thể bạn có thể thực hiện điều đó với re hoặc bằng phần mở rộng Cython đơn giản ?)… Nhưng lợi thế I/O của hệ điều hành biết việc bạn đang làm với ánh xạ có thể làm giảm nhược điểm của CPU.

Thật không may, Python không hiển thị cuộc gọi madvise mà bạn sử dụng để tinh chỉnh mọi thứ nhằm cố gắng tối ưu hóa điều này trong C (ví dụ: thiết lập rõ ràng MADV_SEQUENTIAL thay vì đoán hạt nhân hoặc buộc trang lớn trong suốt) - nhưng bạn thực sự có thể ctypes chức năng ra khỏi libc.

+1

Cảm ơn bạn đã dành thời gian trả lời chi tiết này :) +1 –

+0

Tôi có 30 GB bộ nhớ trên hộp linux. Có bất kỳ vấn đề là làm một readlines() để đưa toàn bộ tập tin vào bộ nhớ? – Reise45

+0

@ Reise45: Nó phụ thuộc vào ý bạn là "vấn đề". Nó nên _work_; 'readlines' trên một file 3GB nên dùng dưới 4GB, và nếu bạn cũng xử lý trước tất cả các dòng vào danh sách các giá trị trong bộ nhớ, không nên nhiều hơn 12GB, vì vậy bạn vẫn ở trong giới hạn thoải mái. Nhưng nó có nghĩa là bạn phải làm tất cả việc đọc lên phía trước, do đó, hệ điều hành không thể giúp đường ống của bạn I/O chờ đợi và CPU của bạn làm việc; bạn lãng phí thời gian vào lỗi malloc và cache; vv Nếu có một số lợi ích (ví dụ: nó cho phép bạn sử dụng NumPy để tăng tốc độ vòng lặp xử lý chậm), điều đó có thể đáng giá, nhưng nếu không, tại sao phải làm như vậy? – abarnert

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