2015-10-13 20 views
7

Giả sử rằng nội dung của tệp Foo.txt như sau.Làm cách nào để bỏ qua bộ nhớ cache của hệ thống tệp khi đọc tệp ở Golang?

Foo Bar Bar Foo 

Hãy xem chương trình ngắn sau đây.

package main 

import "syscall" 
import "fmt" 


func main() { 
    fd, err := syscall.Open("Foo.txt", syscall.O_RDONLY, 0) 
    if err != nil { 
     fmt.Println("Failed on open: ", err) 
    } 
    data := make([]byte, 100) 
    _, err = syscall.Read(fd, data) 
    if err != nil { 
     fmt.Println("Failed on read: ", err) 
    } 
    syscall.Close(fd) 
} 

Khi chúng tôi chạy chương trình trên, chúng tôi không gặp lỗi nào, đó là hành vi đúng.

Bây giờ, tôi sửa đổi dòng syscall.Open thành các dòng sau.

fd, err := syscall.Open("Foo.txt", syscall.O_RDONLY | syscall.O_SYNC | syscall.O_DIRECT, 0) 

Khi tôi chạy lại chương trình, tôi nhận được kết quả sau (không mong muốn).

Failed on read: invalid argument 

Làm thế nào tôi có thể một cách chính xác thông qua các cờ syscall.O_SYNCsyscall.O_DIRECT theo quy định của các open man page cho bỏ qua bộ nhớ cache hệ thống tập tin?

Lưu ý rằng tôi đang sử dụng giao diện syscall tập tin trực tiếp thay vì giao diện os tập tin bởi vì tôi không thể tìm thấy một cách để vượt qua những lá cờ vào các chức năng được cung cấp bởi os, nhưng tôi mở cửa cho các giải pháp sử dụng os với điều kiện chúng hoạt động chính xác để tắt bộ nhớ cache của hệ thống tệp trên lần đọc.

Cũng lưu ý rằng tôi đang chạy trên Ubuntu 14.04 với ext4 làm hệ thống tệp của tôi.


Cập nhật: Tôi cố gắng để sử dụng gói @Nick Craig-Wood trong các mã dưới đây.

package main 

import "io" 
import "github.com/ncw/directio" 
import "os" 
import "fmt" 


func main() { 
    in, err := directio.OpenFile("Foo.txt", os.O_RDONLY, 0666) 
    if err != nil { 
     fmt.Println("Error on open: ", err) 
    } 

    block := directio.AlignedBlock(directio.BlockSize) 
    _, err = io.ReadFull(in, block) 
    if err != nil { 
     fmt.Println("Error on read: ", err) 
    } 
} 

Đầu ra là sau

Error on read: unexpected EOF 
+1

Các bạn đã cố gắng làm mở đọc chặt chẽ với những chính xác đối số trong một cái gì đó khác hơn là đi (C có thể)? Từ những gì tôi có thể thấy trên trang người đàn ông, O_SYNC chỉ ảnh hưởng đến các hoạt động ghi và O_DIRECT cần một số loại bộ đệm có kích thước chính xác (?) Trong không gian người dùng, đây có thể là vấn đề cụ thể, nhưng trước tiên tôi cố gắng làm việc đó trong C ... – mrd0ll4r

+0

@ mrd0ll4r, Thực ra tôi đã chạy [chương trình này] (http://man7.org/tlpi/code/online/book/filebuff/direct_read.c.html) và gặp lỗi tương tự 'EINVAL' trên phía C. Vì vậy, không, nó không đi cụ thể. – merlin2011

Trả lời

1

Từ trang open man, dưới GHI CHÚ:

Cờ O_DIRECT thể áp đặt các hạn chế liên kết vào độ dài và địa chỉ của người sử dụng không gian bộ đệm và độ lệch tập tin của I/O. Trong các hạn chế liên kết Linux khác nhau tùy theo hệ thống tập tin và phiên bản hạt nhân và có thể vắng mặt hoàn toàn.

Vì vậy, bạn có thể có vấn đề căn chỉnh, hoặc bộ nhớ hoặc bù đắp tệp hoặc kích thước bộ đệm của bạn có thể là "sai". Điều chỉnh và kích thước nên là không rõ ràng. Trang người dùng tiếp tục:

Tuy nhiên hiện không có giao diện độc lập cho hệ thống tệp để phát hiện những hạn chế này đối với tệp hoặc hệ thống tệp nhất định.

Và ngay cả Linus nặng, theo cách kín đáo thường thấy của mình:

"Điều đó luôn luôn quấy rầy tôi về O_DIRECT là toàn bộ giao diện chỉ là ngu ngốc, và có lẽ được thiết kế bởi một loạn trí khỉ trên một số chất kiểm soát tâm trí nghiêm trọng. " —Linus

Chúc may mắn!

p.s. Đâm trong bóng tối: tại sao không đọc 512 byte?

+0

Thông tin chi tiết rất thú vị về các biến chứng của việc sử dụng O_DIRECT. Bạn có biết bất kỳ giải pháp nào cho câu hỏi bỏ qua bộ đệm hệ thống tệp trong Go (ngay cả khi nó liên quan đến một tuyến đường hoàn toàn khác) không? Tôi cũng cần một giải pháp. – vastlysuperiorman

5

Bạn có thể sử dụng số directio package mà tôi đã thực hiện cho mục đích này chính xác.

Từ trang web

Đây là thư viện cho ngôn ngữ Go để cho phép sử dụng trực tiếp IO dưới tất cả các hệ điều hành hỗ trợ của Go (trừ OpenBSD và plan9).

IO trực tiếp thực hiện IO đến và từ đĩa mà không cần đệm dữ liệu trong hệ điều hành. Nó rất hữu ích khi bạn đang đọc hoặc viết nhiều dữ liệu mà bạn không muốn lấp đầy bộ nhớ cache của hệ điều hành.

Xem ở đây cho tài liệu gói

http://go.pkgdoc.org/github.com/ncw/directio

+0

Tôi đã cố gắng sử dụng gói của bạn nhưng tôi nhận được 'EOF bất ngờ' khi tôi cố gắng đọc. – merlin2011

+0

@ merlin2011 trong ví dụ của bạn là '" Foo.txt "' lớn hơn 'directio.BlockSize'? –

+0

Nó nhỏ hơn 'directio.BlockSize'. – merlin2011

0

bạn có thể thử sử dụng fadvice và madvice, nhưng không có đảm bảo. cả hai sẽ hoạt động nhiều hơn với các tệp/dữ liệu lớn hơn, vì:

Một phần cố tình giữ gìn bộ nhớ cần thiết hơn là loại bỏ bộ nhớ không cần thiết.

xem mã nguồn Linux, điều gì sẽ làm điều gì đó và nội dung nào không. Ví dụ POSIX_FADV_NOREUSE không làm gì cả.

http://lxr.free-electrons.com/source/mm/fadvise.c#L62

http://lxr.free-electrons.com/source/mm/madvise.c

package main 

import "fmt" 
import "os" 
import "syscall" 

import "golang.org/x/sys/unix" 

func main() { 
    advise := false 
    if len(os.Args) > 1 && os.Args[1] == "-x" { 
     fmt.Println("setting file advise") 
     advise =true 
    } 

    data := make([]byte, 100) 
    handler, err := os.Open("Foo.txt") 
    if err != nil { 
     fmt.Println("Failed on open: ", err) 
    }; defer handler.Close() 

    if advise { 
     unix.Fadvise(int(handler.Fd()), 0, 0, 4) // 4 == POSIX_FADV_DONTNEED 
    } 

    read, err := handler.Read(data) 
    if err != nil { 
     fmt.Println("Failed on read: ", err) 
     os.Exit(1) 
    } 

    if advise { 
     syscall.Madvise(data, 4) // 4 == MADV_DONTNEED 
    } 

    fmt.Printf("read %v bytes\n", read) 
} 

/usr/bin/lần -v ./direct -x

Command being timed: "./direct -x" 
User time (seconds): 0.00 
System time (seconds): 0.00 
Percent of CPU this job got: 0% 
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.03 
Average shared text size (kbytes): 0 
Average unshared data size (kbytes): 0 
Average stack size (kbytes): 0 
Average total size (kbytes): 0 
Maximum resident set size (kbytes): 1832 
Average resident set size (kbytes): 0 
Major (requiring I/O) page faults: 2 
Minor (reclaiming a frame) page faults: 149 
Voluntary context switches: 2 
Involuntary context switches: 2 
Swaps: 0 
File system inputs: 200 
File system outputs: 0 
Socket messages sent: 0 
Socket messages received: 0 
Signals delivered: 0 
Page size (bytes): 4096 
Exit status: 0 
Các vấn đề liên quan