首頁 > 後端開發 > Golang > 主體

GOLANG:為什麼在使用 os.File.Fd() 時 SetDeadline/SetReadDeadline/SetWriteDeadline 對檔案不起作用?

PHPz
發布: 2024-02-09 08:30:21
轉載
1067 人瀏覽過

GOLANG:为什么在使用 os.File.Fd() 时 SetDeadline/SetReadDeadline/SetWriteDeadline 对文件不起作用?

php小編子墨在這篇文章中將為您解答關於Golang中使用os.File.Fd()時SetDeadline/SetReadDeadline/SetWriteDeadline對檔案不起作用的問題。在Golang中,這些方法是用來設定檔案的截止時間,但是有時候可能會出現無效的情況。接下來,我們將探討可能的原因,並提供解決方案來確保這些方法正常運作。

問題內容

我使用 os.File.SetReadDeadlineos.File.ReadFull 的組合。但即使使用 SetReadDeadline,我設定的截止日期也被完全忽略,並且 ReadFull 永遠阻塞。這是為什麼?

其他資訊:我向檔案觸發了一些 IOCTLS,因此需要 os.File.Fd() 來取得檔案描述子。

解決方法

tl;博士:

使用 os.file.fd() 後,在檔案上使用 syscall.setnonblock(fd.fd(), true)

這是由於 read 在 golang unix 中:

func (fd *fd) read(p []byte) (int, error) {
    if err := fd.readlock(); err != nil {
        return 0, err
    }
    defer fd.readunlock()
    if len(p) == 0 {
        // if the caller wanted a zero byte read, return immediately
        // without trying (but after acquiring the readlock).
        // otherwise syscall.read returns 0, nil which looks like
        // io.eof.
        // todo(bradfitz): make it wait for readability? (issue 15735)
        return 0, nil
    }
    if err := fd.pd.prepareread(fd.isfile); err != nil {
        return 0, err
    }
    if fd.isstream && len(p) > maxrw {
        p = p[:maxrw]
    }
    for {
        n, err := ignoringeintrio(syscall.read, fd.sysfd, p)
        if err != nil {
            n = 0
            if err == syscall.eagain && fd.pd.pollable() {
                if err = fd.pd.waitread(fd.isfile); err == nil {
                    continue
                }
            }
        }
        err = fd.eoferror(n, err)
        return n, err
    }
}
登入後複製

如果檔案設定為阻塞模式,第一個 n, err := ignoringeintrio(syscall.read, fd.sysfd, p) 將永遠阻塞。 waitread 僅當檔案以非阻塞模式開啟時才會執行。但我確實以非阻塞模式打開了文件,那麼發生了什麼?

os.file.fd()的實作 破壞了它

func (f *File) Fd() uintptr {
    if f == nil {
        return ^(uintptr(0))
    }

    // If we put the file descriptor into nonblocking mode,
    // then set it to blocking mode before we return it,
    // because historically we have always returned a descriptor
    // opened in blocking mode. The File will continue to work,
    // but any blocking operation will tie up a thread.
    if f.nonblock {
        f.pfd.SetBlocking()
    }

    return uintptr(f.pfd.Sysfd)
}
登入後複製

fd() 始終將檔案設定為阻塞。因此,我們必須在等待輪詢讀取之前撤銷該操作。因此:

使用 os.file.fd() 後,在檔案上使用 syscall.setnonblock(fd.fd(), true)

以上是GOLANG:為什麼在使用 os.File.Fd() 時 SetDeadline/SetReadDeadline/SetWriteDeadline 對檔案不起作用?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:stackoverflow.com
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!